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

Hi, I have written a perl script that is pulling a load of info from a pipe (|) delimited flat file db. Here is the code I use to get the info and use it
open(LOGFILE, $list); @entries = <LOGFILE>; close LOGFILE; &header; foreach $line (@entries) { @fields = split(/\|/,$line); %field = (CassID => $fields[0], CDID => $fields[1], Category => $fields[2], Title => $fields[3], Image => $fields[4], Description => $fields[5], CASS_Price => $fields[6], CD_Price => $fields[7], Artist => $fields[8], CASS_CatNo => $fields[9], CD_CatNo => $fields[10], Database => $fields[11], Label => $fields[12], ID => $fields[13], ); foreach ($line) { print <<EOHtml; html stuff
What I would like to be able to do is sort them by the first letter of the $Field{'Artist'} field. Any help would be greatly appreciated. Cheers, Lloyd.

Replies are listed 'Best First'.
Re: Sorting on a particular field from a Flat File db??
by Russ (Deacon) on Nov 04, 2000 at 21:11 UTC
    my @SortedKeys = sort {$field{$a} cmp $field{$b}} keys %fields;
    We are creating our own sort routine, where we can use the keys in the %fields hash, but compare the values belonging to those keys to perform the sort.

    This will cause a lot of hash lookups, but my benchmarks show that hash lookups are not expensive enough to warrant a Schwartzian Transform.

    <Update> Oops, didn't read the question</Update>

    my @SplitEntries = map{[split( '|', $_)]} @Entries; foreach $Lineref (sort {$a->[8] cmp $b->[8]} @SplitEntries) { my @Fields = @$Lineref; # This will be in sorted order, by Artist Name # $Fields[0] is CassID, $Fields[1] is CDID, etc }
    New explanation: We create arrays of fields from each line, storing them in @SplitEntries (each entry in @SplitEntries is an arrayref holding the fields).

    Now, we can sort the entries on Artist Name.

    This is not the most CPU-efficient way to do this, either. If your music database is really big, you may want to get the Artist Name for each entry and the array index of its line. Then, sort the names and use the indices to get back to the real array.

    my @SplitEntries = map{[split( '|', $_)]} @Entries; my @Names = map{[$_, @SplitEntries[$_]]} @SplitEntries; my @SortedIndices = map {$_->[0]} sort {$a->[1] cmp $b->[1]} @Names; foreach $lineref (@SplitEntries{@SortedIndices}){ my @Fields = @$Lineref; ... }
    Even better, you should consider using DBI and let it manage your sorting needs. ;-)

    Russ
    Brainbench 'Most Valuable Professional' for Perl

RE: Sorting on a particular field from a Flat File db??
by footpad (Abbot) on Nov 04, 2000 at 23:25 UTC
    Lloyd,

    You might also consider taking a peek at the DBI module on CPAN. As you probably know, SQL lets you sort the results of a SQL query using an ORDER BY clause. In keeping with the advice of not re-inventing the wheel, you can use this to shift the sorting burden from your code to a module that's already been written and (presumeably) thoroughly debugged.

    Since DBI supports multiple database formats, this may help you as your application evolves. You're using a simple file format now, but you may wish to choose a different one later. For example, suppose you eventually need transactions, joining, and so on? If you start treating the application as a database, it'll be easier to add this type of support later.

    Of course, it's possible to do the whole thing without using the module, but I've personally found it easier to use database engines earlier than later in an application's lifecycle--even if the application is one no one else will use. (Eventually, you want someone else to use it and....)

    Just a thought for the future...

    -- f
Re: Sorting on a particular field from a Flat File db??
by JP Sama (Hermit) on Nov 04, 2000 at 22:05 UTC
    I'm just guessing... but you could try something like this:
    sort { $field{$a}{'artist'} cmp $amigos{$b}{'artist'} } keys %field;

    I hope this work...
    #!/usr/bin/perl -w
    $tks = `mount`;
    $jpsama = $! if $!;
    print $jpsama;