# Accessing sublists conditional on their length

Say I have a list that looks like this:

list = {{{151.335, 245.102}, {1, 1}}, {{41.435, 245.021}, {2, 2}, {3, 3}},
{{131.048, 243.364}, {3, 3}, {56, 56}, {76, 23}}, {{164.911, 244.039}, {4, 4}},
{{98.1685, 239.618}, {5, 5}}, {{196.333, 239.212}, {6, 6}}, {{184.767, 234.228},
{7, 7}}, {{213.044, 234.24}, {8, 8}}, {{26.6316, 221.423}, {9, 9}}};


How can I return the last element in each sublist conditional on the sublist being a critical length k? For example if we set k=3, we'd return {{3, 3}, {76, 23}} from the above list.

Here's the naive way to do it:

k = 3;

list = {{{151.335, 245.102}, {1, 1}}, {{41.435, 245.021}, {2, 2}, {3, 3}},
{{131.048, 243.364}, {3, 3}, {56, 56}, {76, 23}}, {{164.911, 244.039},
{4, 4}}, {{98.1685, 239.618}, {5, 5}}, {{196.333, 239.212}, {6, 6}},
{{184.767, 234.228}, {7, 7}}, {{213.044, 234.24}, {8, 8}},
{{26.6316, 221.423}, {9, 9}}};
outputList = {};

For[i = 1, i <= Length[list], i++,
If[Length[list[[i]]] >= k,
outputList = Append[outputList, list[[i]][[Length[list[[i]]]]]];
];
];

outputList


Surely there must be a better way?

Select and Cases are usually convenient for these types of things:

(* Select takes a function as second argument and picks element where it is True *)
Select[list, Length[#] >= 3 &][[All, -1]]

(* Cases takes a pattern as second argument and finds all matches
optionally transforming each match according to a rule *)
Cases[list, l_List /; Length[l] >= 3 :> l[[-1]]]

• Thanks, do you know which one is generally faster? – HStoley Sep 13 '13 at 14:05
• @HStoley, Select is generally faster. Especially for larger Lists. – RunnyKine Sep 13 '13 at 14:06

Here's another way:

With[{k = 3},
Pick[list, Unitize[Length /@ list - (k - 1)], 1][[All, -1]]
]


It's a bit faster than Select or Cases

parts = RandomInteger[{2, 5}, 10^5];
data = InternalPartitionRagged[RandomReal[1, {Total[parts], 2}], parts];

With[{k = 3},
l0 = Pick[data, Unitize[Length /@ data - (k - 1)], 1][[All, -1]]
] // timeAvg
(l1 = Select[data, Length[#] >= 3 &][[All, -1]]) // timeAvg
(l2 = Cases[data, l_List /; Length[l] >= 3 :> l[[-1]]]) // timeAvg

(* 0.0524018
0.104487
0.127854 *)

l0 == l1 == l2
(* True *)


This will also work (k=3):

Last /@ Select[list, Length[#] >= 3 &]
`

It takes the last element of each sublist of the list returned by Select.