12

I have a ragged list

ragged = {{a,b,c,d,e},{x,y,z}}

that I would like to trim (on the right) to be rectangular. The desired result is

{{a,b,c},{x,y,z}}

It seems like this should be a one-word operation but I can't find the one word. So far the best I can do is to PadRight with Null and then delete everything with a Null in it.

Transpose[
 DeleteCases[
  Transpose[
   PadRight[
    ragged,
    Automatic,
    Null
    ]
   ],
  a_ /; MemberQ[a, Null]
  ]
 ]

This seems way too complicated for such a simple operation. What is the simplest way to do this?

ArgentoSapiens
  • 7,780
  • 1
  • 32
  • 49

5 Answers5

14

What about:

ragged[[All, 1 ;; Min[Length /@ ragged]]]

{{a, b, c}, {x, y, z}}

Yves Klett
  • 15,383
  • 5
  • 57
  • 124
13

You are looking for Take. To then make the array rectangular, I would do something like this

Take[ragged, All, Min[Length /@ ragged] ]
rcollyer
  • 33,976
  • 7
  • 92
  • 191
9

You could do something like

PadRight[ragged, {Automatic, Min[Length /@ ragged]}]
Heike
  • 35,858
  • 3
  • 108
  • 157
7

Here is a timing comparison of the methods presented. I had to modify Heike's code because it did not work on version 7.

SetAttributes[timeAvg, HoldFirst]

timeAvg[func_] := 
 Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

ragged = RandomReal[99, #] & /@ RandomInteger[{25, 100}, 5000];

PadRight[ragged, {Length@ragged, Min[Length /@ ragged]}]; // timeAvg

ragged[[All, ;; Min[Length /@ ragged]]]; // timeAvg

Take[ragged, All, Min[Length /@ ragged]]; // timeAvg
0.02808

0.002864

0.002744

ragged = RandomReal[99, #] & /@ RandomInteger[{2500, 5000}, 50];

PadRight[ragged, {Length@ragged, Min[Length /@ ragged]}]; // timeAvg

ragged[[All, ;; Min[Length /@ ragged]]]; // timeAvg

Take[ragged, All, Min[Length /@ ragged]]; // timeAvg
0.01688

0.00009184

0.000088896

rcollyer wins!

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
3

In version 10 the package GeneralUtilites contains the functions TrimLeft and TrimRight:

x = {{1, 2, 3}, {1, 2, 3, 4}, {1, 2}};

Needs["GeneralUtilities`"]

TrimLeft[x]
TrimRight[x]
{{2, 3}, {3, 4}, {1, 2}}

{{1, 2}, {1, 2}, {1, 2}}

Burdened with the additional argument testing overhead of a packaged function these are not quite as fast as the raw methods posted earlier but they are sufficient. The core of each is akin to Yves Klett's answer:

lists[[All, -Min[Length /@ lists] ;; All]]

lists[[All, 1 ;; Min[Length /@ lists]]]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371