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

Hi, I have an array that hold first and last names of people, the first and last name are separated with a pipe (|) it looks like this: @names = ("David|Gets","Richard|Storm"); I want to sort this array, sometimes by the first name and sometimes by the last name. (like the unix sort command: sort -k) Can this be doen in perl? thanks.

Replies are listed 'Best First'.
Re: sort by field
by herveus (Prior) on Sep 08, 2004 at 13:29 UTC
    Howdy!

    Yep.

    The sort function can take a subroutine that does the comparison. In this case, a Schwartzian Transform can be really useful.

    @names = map { $_->[0] } sort { $a->[2] cmp $b->[2] } # index 2 for last name, 1 f +or first map { [$_, split(/\|/, $_)] } @names;

    This turns each element of @names into a reference to an array containing the original item plus its two components, sorts that by the appropriate element of those arrays, then extracts the original item.

    yours,
    Michael
Re: sort by field
by Limbic~Region (Chancellor) on Sep 08, 2004 at 13:30 UTC
    tsvi,
    Can this be doen in perl?

    Here are a couple of Perl's mottos:

    • Makes hard things possible and easy things easy
    • There Is More Than One Way To Do It (TIMTOWTDI)

    In this particular case, I would suggest considering changing your data structure. Depending on your situation, you may want an Array of Arrays (AoA) or even an Array of Hashes (AoH). Here are a couple of examples:
    # AoA sorted by first name my @names = ( [ qw( David Gets ) ], [ qw( Richard Storm ) ], ); my @sorted = sort { $a->[0] cmp $b->[0] } @names; # AoH sorted by last name my @names = ( { fn => 'David', ln => 'Gets' }, { fn => 'Richard', ln => 'Storm' }, ); my @sorted = sort { $a->{ln} cmp $b->{ln} } @names;

    Now there are more efficient ways to do this sort and I will leave that up to you - take a look at Super Search. I will be using Schwartzian Transform to answer the question you actually asked.

    # Sorted by first name my @names = qw( David|Gets Richard|Storm ); my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, split /\|/, $_, 2 ] } @names;

    Cheers - L~R

Re: sort by field
by Roy Johnson (Monsignor) on Sep 08, 2004 at 13:31 UTC
    Can this be done in perl?
    Of course! Perl has a built-in sort function that allows you to supply a comparison function so you can specify how you want sorting to be done.
    perldoc -f sort
    For a more tutorial approach, see Randal's article on sorting, in which he introduces the Schwartzian Transform.

    Caution: Contents may have been coded under pressure.
Re: sort by field
by trammell (Priest) on Sep 08, 2004 at 15:44 UTC
    Sort by first name (untested):
    @names = sort @names;
    Sort by last name, using ST (untested):
    @names = map $_->[0], sort { $a->[1] cmp $b->[1] } map { (my $x=$_)=~s/(\w+)\|(\w+)/$2,$1/; [$_,$x] } @names;