lbmp has asked for the wisdom of the Perl Monks concerning the following question:

Esteemed Monks, I would like to sort a multi-dimensional array (LoL), based on the value of a particular subscript in the second-level array.

Here is some test code:
#!/usr/bin/perl my $aref = [[(1..10)], [(30..40)], [qw(the quick brown fox)], [qw(jumps over the lazy dog)] ]; for (@$aref) { print "$_: @$_\n"; } print "\n"; # print some values, just to test whether dereferencing is correct print ${$$aref[0]}[0], "\n"; print $aref->[0]->[0], "\n"; print $aref->[1]->[0], "\n"; print $aref->[2]->[0], "\n"; print $aref->[3]->[0], "\n"; print "\n"; for (sort { $aref->[$a]->[0] cmp $aref->[$b]->[0] } @$aref) { print "$_: @$_\n"; }
This returns:
ARRAY(0x8153c28): 1 2 3 4 5 6 7 8 9 10 ARRAY(0x8154630): 30 31 32 33 34 35 36 37 38 39 40 ARRAY(0x81548a0): the quick brown fox ARRAY(0x8154a50): jumps over the lazy dog 1 1 30 the jumps Out of memory!

An easy work-around (that I can think of) would be to use an intermediate hash (turning the structure into a HoL), then sorting on the hash keys. But I would like to understand why the above code does not work.

Thanks!

-lbmp

Replies are listed 'Best First'.
Re: Sort multi-dimensional array based on dereferenced value - out of memory error
by moritz (Cardinal) on Sep 05, 2011 at 14:44 UTC
    The problem is that $a and $b inside the sort block are array references (and not indexes to them), and you use them as indexes, so as numbers.

    When you use a reference as a number, it evaluates to the memory address of the referencee. This address can be a rather large number, and your code autovivifies an array big enough to hold that many elements.

    $ perl -wE 'say 0 + []' 10034664

    So it tries to create an array with about 10Mio elements on my machine.

    The fix is to use just $a in place of $aref->[$a] in your code

      Aha! Thanks to both of you (Anonymous Monk and moritz) for the clear explanation. Indeed, it works fine when not using $a and $b as indexes.

      Additionally, I noticed that when running with -w, perl tells me exactly what I was doing wrong:

      $ perl -w foo.pl
      Use of reference "ARRAY(0x8153c28)" as array index at foo.pl line 21.
      Out of memory!
      

      Lesson learned!

Re: Sort multi-dimensional array based on dereferenced value - out of memory error
by Anonymous Monk on Sep 05, 2011 at 14:41 UTC
    $a and $b are references not indexes, when treated as a number, they're a big number, use
    $a->[0] cmp $b->[0]