Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

If you have a simple list of lists as follows:

test = {{1, 2}, {4, 5, 6, 7}, {5, 4, 3}}

How do you ask Mathematica to return the sublist of greatest length?

I've been trying to write a Select command using pure functions without success.

share|improve this question
add comment

7 Answers

One possibility:

test = {{1, 2}, {4, 5, 6, 7}, {5, 4, 3}};
lengths = Length /@ test;
max = Max[lengths];
pos = Position[lengths, max];
Extract[test, pos]

gives:

{{4, 5, 6, 7}}

If there are two or more sublists that are of 'greatest length' those will also be returned.

share|improve this answer
    
This is faster than I thought it would be, slightly faster than Last@SortBy[test, {Length}] on my test data, and quite a bit faster than the infix thing. –  Mr.Wizard Feb 5 '12 at 2:26
    
Your solution is the best, though not in price, see mathematica.stackexchange.com/questions/1342/… –  Artes Feb 6 '12 at 11:14
add comment

Reasonably fast and quite direct, but returns only one list if there are ties:

Last@SortBy[test, {Length}]

More whimsical but catching ties (warning: infix ahead):

test ~SortBy~ Length ~SplitBy~ Length // Last

Since Arnoud's method tests the fastest for functions that include ties, here is my terse version of it:

longest[L_List] := L ~Extract~ Position[#, Max@#] &[Length /@ L]
share|improve this answer
add comment

Sort automatically sorts by length, so it is as simple as

Last@Sort@test
share|improve this answer
    
Ah, very nice! It's going to be slower because of all the tiebreaking, but very elegant. –  Mr.Wizard Feb 5 '12 at 2:16
add comment

A solution using Select is :

max = Max[Length /@ test];
Select[test, Length[#] == max &]

This solution and Arnoud's, as well as J.M.'s ones, are better if we have more lists of maximal length. E.g. for

test = {{1, 2}, {4, 5, 6, 7}, {5, 4, 3}, {2, 2, 3, 4}};

this returns

 {{4, 5, 6, 7}, {2, 2, 3, 4}}

Edit

Since one would like to know performance issues of various methods I've made a comparison of presented approaches (only for methods which return all longest sublists) on a very long list from the best to the slowest. On smaller lists proportions of timings may slightly change, but in general, the order is preserved.

longlist = Table[RandomInteger[{-10, 10}, RandomInteger[100]], {10^6}];

{lengths = Length /@ longlist;                                (*Arnoud*)
 max = Max[lengths];
 pos = Position[lengths, max];
 Extract[longlist, pos];} // Timing
(*
==>  {0.422, {Null}}
*)
{max = Max[Length /@ longlist];                               (*Artes*)
Select[longlist, Length[#] == max &];} // Timing
(*
==>  {1.685, {Null}}
*)
Pick[longlist, #, Max[#]] &[Length /@ longlist]; // Timing     (*J.M.*)
(*
==>  {2.012, Null}
*)
longlist~SortBy~Length~SplitBy~Length // Last; // Timing     (*Spartacus*) 
(*
==>  {7.098, Null}
*)
allMaxBy[longlist, Length]; // Timing                        (*Szabolcs*)
(*
==>  {7.144, Null}
*)
share|improve this answer
    
Somewhat different results are had with longlist = RandomInteger[99, #] & /@ RandomInteger[{1, 5000}, 15000]; –  Mr.Wizard Feb 6 '12 at 19:06
    
For this list your method as well as Szabolcs' one seem to be 7 times faster than J.M.'s approach, though more than 2 times slower than mine and 7 times than Arnoud's –  Artes Feb 6 '12 at 19:22
add comment

Alternatively:

test = {{2, 3}, {1, 2}, {4, 5, 6, 7}, {5, 4, 3}, {8, 9, 10, 11}};

Pick[test, #, Max[#]] &[Length /@ test]
{{4, 5, 6, 7}, {8, 9, 10, 11}}
share|improve this answer
add comment

If you only want one item from the resulting list, you can use the two-argument form of Ordering instead of Sort to be a bit more efficient:

test[[Ordering[test, -1]]]

biglist = 
  Table[RandomInteger[10, RandomInteger[100]], {10^5}];

Timing[biglist[[Ordering[biglist, -1]]]]

(*
==> {0.006476, {{10, 10, 10, 3, 4, 7, 4, 3, 9, 8, 8, 1, 2, 1, 5, 
   10, 10, 10, 9, 4, 6, 6, 9, 1, 2, 10, 8, 3, 0, 9, 1, 2, 5, 1, 1, 2, 
   7, 8, 9, 10, 8, 4, 8, 4, 7, 9, 3, 4, 5, 1, 6, 6, 4, 5, 8, 6, 3, 2, 
   6, 4, 9, 9, 9, 7, 1, 10, 4, 2, 10, 8, 0, 8, 1, 0, 9, 10, 7, 4, 5, 
   3, 6, 6, 6, 4, 2, 3, 1, 4, 9, 6, 5, 1, 8, 10, 0, 1, 3, 5, 10, 4}}}
*)

Timing[Last@Sort@biglist]

(*
==> {0.170369, {10, 10, 10, 3, 4, 7, 4, 3, 9, 8, 8, 1, 2, 1, 5, 
  10, 10, 10, 9, 4, 6, 6, 9, 1, 2, 10, 8, 3, 0, 9, 1, 2, 5, 1, 1, 2, 
  7, 8, 9, 10, 8, 4, 8, 4, 7, 9, 3, 4, 5, 1, 6, 6, 4, 5, 8, 6, 3, 2, 
  6, 4, 9, 9, 9, 7, 1, 10, 4, 2, 10, 8, 0, 8, 1, 0, 9, 10, 7, 4, 5, 3,
   6, 6, 6, 4, 2, 3, 1, 4, 9, 6, 5, 1, 8, 10, 0, 1, 3, 5, 10, 4}}
*)
share|improve this answer
    
How could I forget about this one? +2 if I could! (It should be noted that this only returns one list and not ties.) –  Mr.Wizard Feb 5 '12 at 3:30
1  
This returns only one list of the highest length as R.M.'s and Spartacus' ones do, so these are not the full solutions. –  Artes Feb 5 '12 at 10:49
add comment

I sometimes use a little function MaxBy, made to be analogous with SortBy:

MaxBy[list_, fun_] := list[[First@Ordering[fun /@ list, -1]]]

You need the largest element by length, so you can evaluate

MaxBy[data, Length]

Note: this is based on the same principle as @Brett's solution, but it is slower. @Brett's and @R.M's exploit the fact that Mathematica sorts by length by default, while my solution explicitly uses Length. I still think it's a useful little function, so I shared it again.

The problem with MaxBy is that it only returns a single element, while there may be more than one list of the same length. Here's a somewhat slow but simple implementation that returns all maxima:

allMaxBy[data_, fun_] := Last@SplitBy[SortBy[data, fun], fun]
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.