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$

3 Answers 3

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$
1
  • $\begingroup$ And there it is, in the "details and options" of the documentation. Apologies for missing that before posting. Thanks for explaining. $\endgroup$ Aug 9, 2017 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$
5
  • $\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$ Aug 9, 2017 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, 2017 at 19:25
  • 1
    $\begingroup$ You can extend it to fpos[list_, pos_] := Position[list, Insert[{a_, a_}, Blank[], pos]] $\endgroup$
    – eldo
    Aug 9, 2017 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$ Aug 9, 2017 at 19:41
  • $\begingroup$ @eldo That's exactly what I was looking for! $\endgroup$ Aug 9, 2017 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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