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

Sorry, but this is a newbie question. I have a CGI that takes in five user inputs and saves that to a delimited text file that logs all such input. The script then pulls all of the data back out of the file and sorts the data. The data is brought back into the script and stored in separate arrays for the individual elements. In other words, the first data element is "Date" in the form "20010712". The second array is "Provider", the third is "Description", etc. I want to sort the "Date" array, but I also want the other elements of the other arrays to be sorted consistent with the changes made to the "Date" array. The only way I know how to do this is with a bubble sort. I wrote the following, which ain't workin' so good. Can anyone point me in the right direction? I know how to do this in Basic using line numbers, but I can't get it done in Perl. __________________________________________________
# get total number of data lines entered # by using the "date" array $totalentries = $#date; # move it up one to make the count accurate $totalentries = $totalentries + 1; # Bubble Sort Data # set a Flag $flag = 1; until ($flag == 0) { $n = 0; $counter = $totalentries; $flag = 0; # the flag is changed from 1 to 0. # Not sure if the "until" function will drop out # at this point or not. Don't know a better way. . . while ($counter > 0) { $n2 = $n + 1; if (int $date[$n] < int $date[$n2]) { # if this is true, perform the swap of # the same elements in each array $placeholder = $date[$n]; $date[$n] = $date[$n2]; $date[$n2] = $placeholder; $placeholder = $provider[$n]; $provider[$n] = $provider [$n2]; $provider[$n2] = $placeholder; $placeholder = $description[$n]; $description[$n] = $description[$n2]; $description[$n2] = $placeholder; $placeholder = $exhibit[$n]; $exhibit[$n] = $exhibit[$n2]; $exhibit[$n2] = $placeholder; $placeholder = $page[$n]; $page[$n] = $page[$n2]; $page[$n2] = $placeholder; # if a change occurred, change the flag to "1" $flag = 1; } ++$n; --$counter; } }

Replies are listed 'Best First'.
Re: bubble sort problems
by arturo (Vicar) on Jul 12, 2001 at 19:27 UTC

    Perl has a built in sorting mechanism based on the qsort algorithm, which is usually *much* faster than a bubble sort.

    For examples and some info on using the built-in sort, you can start off with perlfunc:sort, but I also recommend the Complex sorting node in the Tutorials section.

    Hope that helps!

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
Re: bubble sort problems
by Masem (Monsignor) on Jul 12, 2001 at 19:29 UTC
    Perl has a very nice built in sort operator; it's almost always better to use that than a homerolled one.

    In this case, I offer two suggestions; first, use sort's ability for any sort specification to sort by the fields in the order that you want; and second, to sort using the indices instead of elements, then using one addition loop to move things into place if you are starting with separate arrays.

    # @date, @provider, @description, and @page are defined # elsewhere. my @indices = sort { $date[$a] <=> $date[$b] || $provider[$a] cmp $provider[$b] || $description[$a] cmp $description[$b] || $exhibit[$a] cmp $exhibit[$b] || $page[$a] <=> $page[$b] } (0..$#date); @date = map { $date[ $_ ] } @indices; @provider = map { $date[ $_ ] } @indices; # etc etc...

    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: bubble sort problems
by VSarkiss (Monsignor) on Jul 12, 2001 at 19:30 UTC

    Waah! Mommy, the bad man hurt my eyes. ;-)

    First, don't use parallel arrays. That is so Perl4. Make a nice array of arrays, probably like this:

    ($placeholder, $page, $date, ...) = split; push @raw, [ $placeholder, $page, $date ... ];
    Look at data structures cookbook for more.

    Second, a monstrously efficient quicksort is built in to Perl. @sorted = sort { $a->[2] cmp $b->[2] } @raw;(Assuming $date is element 2 of the array, as outlined in the first example.) Et voila.

    HTH

swapping elements efficiently (boo)
by boo_radley (Parson) on Jul 12, 2001 at 20:17 UTC
    People have covered the usage of sort, but I think this is also worth mentioning -- when you're swapping two elements, it's not required to use a placeholder. Perl (at least 5.6) allows you to declare anonymous arrays, and abuse them for the greater good.

    compare

    $placeholder = $date[$n]; $date[$n] = $date[$n2]; $date[$n2] = $placeholder;
    with
    ($date[$n], $date[$n2])=($date[$n2], $date[$n]);

    each one swaps the contents of $date[$n] and $date[$n2], but there's (IMO) clarity in the second one, as well as a reduction in line count. Here's a small sample to flesh out the idea :
    my @foo; $foo[0]=0; $foo[1]=1; print "@foo\n"; ($foo[0], $foo[1])=($foo[1], $foo[0]); print "@foo\n";
      or even terser, change:

      ($date[$n], $date[$n2])=($date[$n2], $date[$n]);
      to:
      @date[$n, $n2] = @date[$n2, $n];
        True dat.
        I was working on a script where 2 arrays got swapped around, so an array slice wasn't possible.