# Select Pairs in a List

We have a list as

list = {{h, {{1, 1, 2}, {1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 3, 1}, {2,
2, 1}, {2, 1}}}, {r, {{1, 1, 2}, {3, 4}, {2, 1}, {2, 4}, {2, 1,
5}}}};


We wish to have another list containing just pairs:

list = {{h, { {1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 1}}}, {r, { {3, 4}, {2, 1}, {2, 4}}}};


How can we use Pick or Select or other functions for this aim?

Select can be used to identify pairs in sub-lists, such as

Select[list[[1, 2]], Length@# == 2 &]

(* {{1, 3}, {1, 4}} *)


Then, use Map to apply Select to every sub-list:

{First@#, Select[Last@#, Length@# == 2 &]} & /@ list

(* {{h, {{1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 1}}}, {r, {{3, 4}, {2, 1}, {2, 4}}}} *)

• I could understand. it is amazing solution. Without using additional IF condition which was in my decesion – Unbelievable May 3 '17 at 5:24

I think you'll find the simple

DeleteCases[list, {_, _, __}, {3}]


to be a bit more efficient...

• simple and efficient...+1 winner for me:) – ubpdqn May 3 '17 at 6:59

Using Apply

f[x_, y_] := {x, y};
f[___] := Nothing;
Apply[f, list, {3}]


Using ReplaceAll (/.)

list /.  {_Integer, _Integer, __} :> Nothing


One needs to carefully specify the replacement rules however, try for example

list /.  {_, _, __} :> Nothing
(* Nothing *)


Rule replacement is actually quite efficient (relatively speaking) in this case, compare the above to @ciao's answer:

testList = Join[Apply[Sequence]@Table[list, 200000]]

(res1 = testList /.  {_Integer, _Integer, __} :> Nothing); // AbsoluteTiming
(* {2.55462, Null} *)
(res2 = DeleteCases[testList, {_, _, __}, {3}]); // AbsoluteTiming
(* {0.769297, Null} *)
res1 == res2
(* True *)


For a solution based on rule replacement a factor of ~3 worse than the (supposedly) fastest method isn't half bad.

• One needs to carefully specify the replacement rules... well how about Replace[list, {_, _, __} :> Nothing, {3}]? – LLlAMnYP May 3 '17 at 8:10
• @LLlAMnYP that one works as well but I though it less general (but maybe safer to use) in case of more deeply nested lists – Sascha May 3 '17 at 8:17

Pattern Matching:

xss = {{h, {{1, 1, 2}, {1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 3, 1}, {2,
2, 1}, {2, 1}}}, {r, {{1, 1, 2}, {3, 4}, {2, 1}, {2, 4}, {2, 1,
5}}}}
xss //. {xs___, {_Integer, _Integer, __}, ys___} -> {xs, ys}


Test (Special Case, 200000 copies of xss):

xss = {{h, {{1, 1, 2}, {1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 3, 1}, {2,
2, 1}, {2, 1}}}, {r, {{1, 1, 2}, {3, 4}, {2, 1}, {2, 4}, {2, 1,
5}}}}
testList = Join[Apply[Sequence]@Table[xss, 200000]]
f[xss_] := f[xss] =
xss //. {xs___, {_Integer, _Integer, __}, ys___} -> {xs, ys}
AbsoluteTiming[testList // Map[f] ]


• Using ReplaceRepeated this way is very inefficient. – Sascha May 3 '17 at 7:21
• The execution time is 0.000057 seconds. {0.000057, {{h, {{1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 1}}}, {r, {{3, 4}, {2, 1}, {2, 4}}}}} – UnchartedWorks May 3 '17 at 7:29
• try the same with a longer list e.g. a form of testlist from my answer (maybe with 1000 copies of the original list) – Sascha May 3 '17 at 7:41
• Memoization is cheating ;-). You are memoizing just three inputs, this is not a representative test. – LLlAMnYP May 3 '17 at 8:01
• @Sascha precisely. But Map[# //. {xs___, {_Integer, _Integer, __}, ys___} :> {xs, ys} &, testList, {2}] is okay-ish. – LLlAMnYP May 3 '17 at 8:08

An example with MapAt:

MapAt[Cases[#, _?(Length@# == 2 &)] &, list, {All, 2}]


yielding:

(* {{h, {{1, 3}, {1, 4}}}, {k, {{1, 3}, {2, 1}}}, {r, {{3, 4}, {2,
1}, {2, 4}}}}*)