http://qs321.pair.com?node_id=181658

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

Say for example I had an array that I created by reading in a file, so:
while ( <INPUT_FILE>) { my ($name, $id, $address, $phone) = split(','); push(@outputRef, $name, $id, $address, $phone); }
Then if I wanted to do an ascending sort on the @outputRef array ONLY BY name and phone number, how would I do that? I would really appreciate help on this, if you know how to do this then thanks a lot in advance. Brent.

Replies are listed 'Best First'.
Re: How do you specify which fields to sort by when sorting an array.
by chromatic (Archbishop) on Jul 14, 2002 at 22:51 UTC
    There are several examples given in the documentation for sort. The trick is specifying which fields of $a and $b to compare:
    my @output; while (<INPUT_FILE>) { push @output, [ split(',', $_, 4) ]; } my @sorted = sort { $a->[0] cmp $b->[0] || $a->[3] <=> $b->[3] } @output;
    I took the liberty of fixing the name of @outputRef (which is not a reference) and pushing each row as an anonymous array. I also use numeric comparisons on the phone numbers.
Re: How do you specify which fields to sort by when sorting an array.
by tadman (Prior) on Jul 15, 2002 at 04:37 UTC
    I'm not sure why chromatic seemed to miss the boat on this one. Although I might be wrong, it would seem that the linefeed ("\n") is being left on the fourth element of the array. Maybe a rushed posting. Here's a more compacted version:
    my @output = sort { $a->[0] cmp $b->[0] || $a->[3] <=> $b->[3] } map { chomp; [ split(',', $_, 4) ] } <INPUT_FILE>;
    Remember that with this kind of structure the data flows from the bottom up. From the file, through the map which makes the proper array-of-arrays (AoA), and in to the sort routine which re-orders it before storing the result in @output.

    As a note, though, comparing phone numbers numerically is pretty lacking. If one has a dot and the other a dash, your sort is going to be ruined. Here's a more robust version that only sorts the numerical component of the phone number, ignoring brackets, dashes and the like:
    sub phone_value { my ($v) = @_; $v =~ tr/^0-9//d; return $v; } my @output = sort { $a->[0] cmp $b->[0] || phone_value($a->[3]) <=> phone_value($b->[3]) } map { chomp; [ split(',', $_, 4) ] } <INPUT_FILE>;