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$ Commented 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$ Commented 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$ Commented Aug 9, 2017 at 19:25
  • 1
    $\begingroup$ You can extend it to fpos[list_, pos_] := Position[list, Insert[{a_, a_}, Blank[], pos]] $\endgroup$ Commented 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$ Commented Aug 9, 2017 at 19:41
  • $\begingroup$ @eldo That's exactly what I was looking for! $\endgroup$ Commented Aug 9, 2017 at 19:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.