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

Monks,

Forgive me if this is truly a novice question.

I have a data file that is broken out like this:
id|projname|status|submitdt|assign_dt|total|complete_dt|person|dept|cl +osed_dt
Currently, this data is stored in an Array called @Data. If The data is already sorted on the id. How can I sort it by the 2nd element in the array "projname" or the 8th element "person" or the 9th element "dept?" I'm using this on a web page so I would like for people to be able to view the output data in ways more meaningful to them.

Thanks in advance,
Louis

Replies are listed 'Best First'.
Re: How to sort an array
by davorg (Chancellor) on Jul 07, 2004 at 13:00 UTC
    The naive way...
    @Data = sort by_projname @Data; sub by_projname { return (split /\|/, $a)[1] cmp (split /\|/, $b)[1]; }
    And similarly for the other columns. But you may like to consider a Schwartzian Transform as it might be more efficient.
    @Data = map { $_->[0] } sort { $_->[1] cmp $_->[1] } map { $_, [ (split /\|/)[1] ] } @Data;
    (that's for sorting by projname - change the index in the bottom map for other columns)
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: How to sort an array
by jarich (Curate) on Jul 07, 2004 at 13:23 UTC
    Just to be clear, you have an array consisting of lines like the one you describe above? So your data could be constructed with something like the following?
    my @Data = ( "1|someproject|active...", "2|somethingelse|finished..." );
    If that is correct, then you can use something like the following to achieve your aim:
    #!/usr/bin/perl -wT use strict; # position to sort by my $sortbyfield = 3; my @input = ( '1|2|1|4|5|6|7|8|9', '1|2|2|5|5|6|7|8|9', '1|2|0|1|5|6|7|8|9', '1|2|9|2|5|6|7|8|9', '1|2|8|3|5|6|7|8|9', '1|2|7|4|5|6|7|8|9', '1|2|6|7|5|6|7|8|9', ); # Schwartzian Transform my @output = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [$_, getfieldvalue($_, $sortbyfield)] } @input; print join( "\n", @output), "\n"; sub getfieldvalue { my ($line, $fieldno) = @_; my @items = split /\|/, $line; return $items[$fieldno]; } __END__ returns (sorted by 3rd _position, arrays start at 0) 1|2|0|1|5|6|7|8|9 1|2|9|2|5|6|7|8|9 1|2|8|3|5|6|7|8|9 1|2|1|4|5|6|7|8|9 1|2|7|4|5|6|7|8|9 1|2|2|5|5|6|7|8|9 1|2|6|7|5|6|7|8|9
    Please note that the above will only work for numeric input. You can change it to use string compare by replacing the <=> with cmp.

    I would suggest thinking about what you're doing with this data, however. If you're going to be accessing bits of it more than just this time, then perhaps you should be using an array of hashes or at least and array of arrays? See perlreftut.

    If you break this into an array of hashes:

    my @fields = qw/id projname status submitdt assign_dt total complete_dt person dept closed_dt/; # Create my array of hashes. foreach (@Data) { my %hash; @hash{@fields} = split /\|/, $_; $_ = \%hash; }
    You can access individual items as follows:
    print "The id of the project in Data[0] is $Data[0]{id}\n";
    This might make it easier to sort, too.
    my @sorted = sort {$a->{projname} cmp $b->{projname}} @Data; # To get the same kind of format as before ... foreach (@sorted) { my %temp = %$_; print "@temp{@fields}\n"; }
    As I said, it depends on how much manipulation is required on the input.

    I hope this helps

    jarich

Re: How to sort an array
by ishnid (Monk) on Jul 07, 2004 at 14:59 UTC
    This is the sort of situation Sort::Fields is designed for:
    use Sort::Fields; # sort on the second element (i.e. element #1) @sorted = fieldsort '\|', [1], @lines;
Re: How to sort an array
by gellyfish (Monsignor) on Jul 07, 2004 at 13:07 UTC

    You probably want to start by looking at 1836 as this has loads of information on the subject of sorting, this is also a good paper on the subject.

    /J\

Re: How to sort an array
by pbeckingham (Parson) on Jul 07, 2004 at 13:07 UTC

    I create an HoA as a holder for the data. Change the index in the sort line in the for loop.

    #! /usr/bin/perl -w use strict; my %data; while (my $line = <DATA>) { chomp $line; my @array = split '\|', $line; my $key = shift @array; $data{$key} = \@array; } #for (sort keys %data) for (sort {$data{$a}[0] cmp $data{$b}[0]} keys %data) { print $_, '=', join (', ', @{$data{$_}}), "\n"; } __DATA__ 1|name9|blah|blah|blah 2|name8|blah|blah|blah 3|name7|blah|blah|blah 4|name6|blah|blah|blah 5|name5|blah|blah|blah 6|name4|blah|blah|blah 7|name3|blah|blah|blah 8|name2|blah|blah|blah 9|name1|blah|blah|blah

Re: How to sort an array
by wufnik (Friar) on Jul 07, 2004 at 13:10 UTC
    here is how to do it using the famed schwarzian transform (ST). by 'it' i mean sort on various fields in your __DATA__. first, though, take your data and append it underneath the "__DATA__" tag. adjust $fieldtosort to taste.

    my $fieldtosort = 9; # person, for now. my @data = <DATA>; my @sorted = map { $_->[0] } sort sortf map { [$_, split /\|/ ] } @data; print @sorted; # sort by $fieldtosort sub sortf { $a->[$fieldtosort] cmp $b->[$fieldtosort]; } __DATA__ id|projname|status|submitdt|assign_dt|total|complete_dt|person|dept|cl +osed_dt
    ...wufnik

    -- in the world of the mules there are no rules --