# Using select to pick out elements of nested lists in an odd way

Suppose I have a nested list such as,

{{{A, B}, {A, D}}, {{C, D}, {A, A}, {H, A}}, {{A, H}}}


Where the elements of interest are,

{{A, B}, {A, D}}

{{C, D}, {A, A}, {H, A}}

{{A, H}}


How would I use select to pick up only elements that contain two or more As in the first part of their sub-elements. In this example I would want the following as an output,

{{A,B},{A,D}}

• This does it: Cases[{{{A, B}, {A, D}}, {{C, D}, {A, A}, {H, A}}, {{A, H}}}, {___, {A, _}, ___, {A, _}, ___}] Commented Jul 28, 2014 at 19:29
• Yep this is exactly what I am looking for. Thank you. Commented Jul 28, 2014 at 19:35

list = {{{a, b}, {a, d}}, {{c, d}, {a, a}, {h, a}}, {{a, h}}}

Pick[list, Count[#[[All, 1]], a] >= 2 & /@ list]


or

Select[list, Count[#[[All, 1]], a] >= 2 &]


or

Cases[list, _?(Count[#[[All, 1]], a] >= 2 &)]


or

DeleteCases[list, _?(! Count[#[[All, 1]], a] >= 2 &)]


all give

{{{a, b}, {a, d}}}

• This is probably the best answer, since it uses the select command explicitly. Thanks! Commented Jul 28, 2014 at 20:23
• @kguler executing your Select with, f.e., list = {{{a, b}, {c, a}}, {{c, d}, {a, a}, {h, a}}, {a, h}, {{a, b}, {a, c}}, {{a, b}, {q, r}, {a, d}}} I get an error message and a result which is, the question being utterly ambigous, debatable.
– eldo
Commented Jul 28, 2014 at 20:37
• @eldo, good observation re implicit assumption that is the source of the error message: although OP's example has that structure, it is not explicitly stated that all sublists have depth >=2. However -- removing {a,h} or changing it to {{a,h}} -- I don't understand why the result is "debatable".
– kglr
Commented Jul 28, 2014 at 20:55
• @kguler - This question has a short history of accepted and de-accepted answers and comments which were subsequently deleted. "Debatable" because the OP is unsure about what he really wants. Hopefully, your excellent answer stays awarded. (But a Case-solution would be more appropriate imo) :)
– eldo
Commented Jul 28, 2014 at 21:13
• @eldo, I see. I missed the deleted comments. And I now see why the wording "elements that contain two or more As in the first part of their sub-elements" could be read differently from my reading of it -- of course, with the help of desired output -- as " two or more elements whose first part is equal to A"
– kglr
Commented Jul 28, 2014 at 21:23

I chose a slightly different formulation:

expr = {{{A, B}, {A, D}}, {{C, D}, {A, A}, {H, A}}, {{A, H}}};

Select[expr, Count[#, {A, _}] > 1 &]

{{{A, B}, {A, D}}}


I will note that this form is faster all four in the Accepted answer:

list = RandomChoice[CharacterRange["A", "H"], {500000, 3, 2}];

Select[list, Count[#, {"A", _}] > 1 &]                  // Timing // First

Pick[list, Count[#[[All, 1]], "A"] >= 2 & /@ list]      // Timing // First
Select[list, Count[#[[All, 1]], "A"] >= 2 &]            // Timing // First
Cases[list, _?(Count[#[[All, 1]], "A"] >= 2 &)]         // Timing // First
DeleteCases[list, _?(! Count[#[[All, 1]], "A"] >= 2 &)] // Timing // First


0.592804

0.795605
0.811205
0.936006
1.060807

list = {{{A, B}, {A, D}}, {{C, D}, {A, A}, {H, A}}, {{A, H}}};


Using Position and Extract:

Extract[#, Position[#, m_?MatrixQ /; Count[m[[All, 1]], A] > 1]] &@list

(*{{{A, B}, {A, D}}}*)


Or using Replace:

Replace[list, m_?MatrixQ /; Count[m[[All, 1]], A] <= 1 :> Nothing, {1}]

(*{{{A, B}, {A, D}}}*)

list = {{{a, b}, {a, d}}, {{c, d}, {a, a}, {h, a}}, {{a, h}}};

p = Position[list, x_ /; Count[First /@ x, a] <= 1, 1, Heads -> False]


{{2}, {3}}

Delete[p] @ list


{{{a, b}, {a, d}}}

MapAt[Nothing, p] @ list


{{{a, b}, {a, d}}}

list = {{{A, B}, {A, D}}, {{C, D}, {A, A}, {H, A}}, {{A, H}}};

If[Count[First /@ #, A] >= 2, #, ## &[]] & /@ list


{{{A, B}, {A, D}}}