3
$\begingroup$

I have a list of n dimensional vectors (n=3 in this example). I want to find the position of all vectors for which all elements other than the $i^{th}$ element are equal to some value (2 in this example) and the value of the $i^{th}$ element is not restricted. I've been using the following approach: Create a pattern test that, when applied to a vector (i) deletes the ith element, (ii) deletes duplicates from the remaining elements, and (iii) checks whether the remaining list of non-duplicates is equal to {2}.

points = {{0, 1, 2}, {2, 4, 2}, {2, 1, 2}, {2, 3, 4}};
Position[points, _?(DeleteDuplicates[Delete[#, 2]] == {2} &),{1}]

This approach works, but in the process I see several of the following messages:

Part 2 of List does not exist

Just to make sure my pattern test function is working, I tried

(DeleteDuplicates[Delete[#, 2]] == {2} &) /@ points
(*{False, True, True, False}*)

The messages go away if I change my pattern test by including List immediately after the underscore:

Position[points, _List?(DeleteDuplicates[Delete[#, 2]] == {2} &),{1}]

As I am already providing a level specification, why is the _List necessary to avoid these messages? What is happening when _List is not included?

$\endgroup$
5
$\begingroup$

It's because Position looks at Heads as well by default:

points = {{0, 1, 2}, {2, 4, 2}, {2, 1, 2}, {2, 3, 4}};
Position[points, _?(DeleteDuplicates[Delete[#, 2]] == {2} &),{1}, Heads->False]

{{2}, {3}}

You could debug this by using TracePrint:

TracePrint[
    Position[points, _?(DeleteDuplicates[Delete[#,2]]=={2}&), {1}],
    _DeleteDuplicates
]

DeleteDuplicates[Delete[List,2]]

Delete::partw: Part 2 of List does not exist.

Delete::partw: Part 2 of List does not exist.

DeleteDuplicates[Delete[{0,1,2},2]]

DeleteDuplicates[{0,2}]

DeleteDuplicates[Delete[{2,4,2},2]]

DeleteDuplicates[{2,2}]

DeleteDuplicates[Delete[{2,1,2},2]]

DeleteDuplicates[{2,2}]

DeleteDuplicates[Delete[{2,3,4},2]]

DeleteDuplicates[{2,4}]

{{2}, {3}}

Notice the DeleteDuplicates[Delete[List,2]] output.

$\endgroup$
  • $\begingroup$ And there it is, in the "details and options" of the documentation. Apologies for missing that before posting. Thanks for explaining. $\endgroup$ – FalafelPita Aug 9 '17 at 17:30
3
$\begingroup$
points = {{0, 1, 2}, {2, 4, 2}, {2, 1, 2}, {2, 3, 4}};
check[list_] := DeleteDuplicates[Delete[list, 2]] == {2};
Position[points,Except[List, _?check], {1}]

(* {{2}, {3}} *)
$\endgroup$
2
$\begingroup$
Position[points, {a_, _, a_}]

{{2}, {3}}

$\endgroup$
  • $\begingroup$ Could this approach be easily extended so that it could take, as an argument, the position of the element one wants to ignore? For example, it would generate {_,a_,a_} for argument value 1 and {a_,a_,_} for argument value 3? $\endgroup$ – FalafelPita Aug 9 '17 at 19:25
  • $\begingroup$ @eldo i realized we can use OrderlessPatternSequence in your approach to make it generic i.e. Position[points, {OrderlessPatternSequence[a_, _, a_]}] $\endgroup$ – Ali Hashmi Aug 9 '17 at 19:25
  • 1
    $\begingroup$ You can extend it to fpos[list_, pos_] := Position[list, Insert[{a_, a_}, Blank[], pos]] $\endgroup$ – eldo Aug 9 '17 at 19:40
  • $\begingroup$ @AliHashmi In my case I do care about the order, I just want to use every order separately. Your example led me to discover Sort[Permutations[{a_,_,a_}]], which would do the job. Thanks. $\endgroup$ – FalafelPita Aug 9 '17 at 19:41
  • $\begingroup$ @eldo That's exactly what I was looking for! $\endgroup$ – FalafelPita Aug 9 '17 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.