# Find position of sublists containing a given element at nth position

I have a list of lists similar to this:

L = {{"a", "b", "c"}, {"x", "c", "y"}, {"i", "j", "h"}, {"x", "b", "z"}}


Each list within L happens to be of length 3. Suppose I need to find the position of the lists that have a particular element (say, "b") at the $$n^{th}$$ position. How can I do this efficiently?

Currently, I have an approach that works but I don't think it is very efficient inefficient (it creates a new list with the $$n^{th}$$ elements and then looks for the queried element, I'm sure there's a way to search L directly):

queriedElement = "b";

queriedPosition = 2;

occurencePositions = Flatten@Position[#[[queriedPosition]] & /@ L, queriedElement]//AbsoluteTiming


{0.000035, {1, 4}}


Searching for an alternative efficient way because I need to do this in large lists.

Thanks!

• As shown by kglr, Position[L[[All,2]], "b"] is probably close to the 'canonical' solution, and it might be of interest that if you don't Flatten, the result may be used directly with Extract to obtain the full sublists, if desired: Extract[L,%] – user1066 May 9 '20 at 19:27

Flatten @ Position[L, _List?(#[[2]] === "b" &)]

{1, 4}


Making it a function:

posF1 = Flatten @ Position[#, _List?(Function[x, x[[#2]] === #3])] &;

posF1[L, 2, "b"]

 {1, 4}


Alternatively,

posF2 = Flatten @ Position[#[[All, #2]], #3] &;

posF2[L, 2, "b"]

 {1, 4}


Also

posF3 = PositionIndex[#[[All, #2]]]@#3 &;

posF3[L, 2, "b"]

 {1, 4}

• As you are comparing against a string, it is better to use === instead of ==: #[[2]] === "b". – J. M.'s torpor May 9 '20 at 12:50
• Thank you @J.M. Edited to change == to ===. – kglr May 9 '20 at 13:52

I tried a solution with Pick.

f[v_,p_,e_]:=Pick[Range[Length[v]], v[[All, p]], e]


where v is your L, p is your queriedPosition and e is your queriedElement.

Here is a timing test of Pick, along with the functions from @kglr.

Block[{element, position, list, posF1, posF2, posF3},
element = "a";
position = 1;
posF1 = Flatten@Position[#, _List?(Function[x, x[[#2]] === #3])] &;
posF2 = Flatten@Position[#[[All, #2]], #3] &;
posF3 = PositionIndex[#[[All, #2]]]@#3 &;
list = RandomChoice[CharacterRange["a", "j"], {2000, 3}];
First /@ {
RepeatedTiming[f[list, position, element]],
RepeatedTiming[posF3[list, position, element]],
RepeatedTiming[posF2[list, position, element]],
RepeatedTiming[Flatten@Position[list, _List?(#[[position]] === element &)]],
RepeatedTiming[posF1[list, position, element]]
}
]


Sample output:

{0.000125, 0.000200, 0.0002303, 0.00248, 0.0030}