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

Dear Monks--

I have a an array of an arrays that looks like this:
$courselist[$courseindex] = [$Institution, $CourseNumber, $Professor, +$CourseTitle, $Enrollment]
I'd like to sort it by $Institution and within that sort by $CourseNumber (and possibly other values). E.g. the array starts like:
$courseindex[0] = ["UM", "CS 34", ......] $courseindex[1] = ["AC", "PHIL 13", ....] $courseindex[2] = ["UM:, "BIO 567', ....]
and I want it to end like this:
$courseindex[0] = ["AC", "PHIL 13", ....] $courseindex[1] = ["UM", "BIO 567', ....] $courseindex[2] = ["UM", "CS 34", ......]
I haven't been able to figure out how to do it.

I tried using something like:
@courselist = sort {$$a[n] cmp $$b[n]} @courselist;
(with various values for n) which worked for me in another program with a similar, but less complex problem, but in this one I'm getting this error message:

"Modification of a read-only value attempted"

Which I can't figure out.

Anyway, that may be the wrong way to go about this problem at hand.

Any clarifications or suggestions would be welcome!

Thanks!

Replies are listed 'Best First'.
Re: sorting an array of an arrays
by Tanktalus (Canon) on Aug 13, 2006 at 00:26 UTC

    First comment is that I'd suggest an array of hashes over an array of arrays because I find it way easier to read a hash than an array when it's a list of disparate objects. Your outer array is really a list of courses - lists are what arrays are for. Your inner arrays are all a single course with a bunch of attributes - attributes are what hashes are good at. However, that probably doesn't change how to sort in your mind, so it's not going to solve your problem.

    To sort on multiple fields, you just need to set up your sorting on those fields. It should be as simple as:

    @courselist = sort { $a->[0] cmp $b->[0] or $a->[1] cmp $b->[1] } @courselist;
    That way, if the 0's are identical (thus cmp return 0, or false), the or kicks in and we check the next one in the list.

    Hope that helps,

      People vary on whether a hash style presentation would be visually clearer. For me it's far clearer to have just the data, lined up in columns. Having keys repeated on each line is, for me, visual clutter which I have to screen out, and it doesn't add information in a case like this where the type of each field is pretty much clear from the content.

      Conceptually, it's a good rule to have like things in arrays, and unlike things in hashes, and I think that rule gets fairly wide agreement. Perceptual styles are different. What may be helpful markers for tanktaus are visual noise that needs to be screened out for slower readers like me. One man's sushi is another man's bait.

Re: sorting an array of an arrays
by bobf (Monsignor) on Aug 13, 2006 at 02:37 UTC
Re: sorting an array of an arrays
by friedo (Prior) on Aug 13, 2006 at 00:25 UTC
    This should do the trick:

    @courseindex = sort { $a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] } @courseindex;
sorting homework?
by aufflick (Deacon) on Aug 13, 2006 at 07:01 UTC
    Forgive me if i'm wrong, but this sounds exactly like the sort of problem that one gives to students (using a familiar dataset like University courses). Gnat53's sole other post also sounds remarkably homework-ish. Gnat53 and reply-ers should refer to Homework Alert! and consider their options!

    I do commend Gnat53's attempt at the solution and also bobf's helpful resource reply.

Re: sorting an array of an arrays
by Gnat53 (Novice) on Aug 13, 2006 at 12:52 UTC
    Dear Monks--

    Not homework!

    I'm a bookseller who's straying into the realm of web-building and perl programming. (www.amherstbooks.com is all mine, for better or worse.) I did spend a lot of time looking at some of the offered resources and still found it difficult to figure out how to do it.
    Thank you all for your help!

    Nat
      Your description of what you wanted was pretty good:
      I'd like to sort it by $Institution and within that sort by $CourseNumber (and possibly other values)
      You just needed to break it down into pieces that perl can understand. "sort it by" you correctly translated as $$a[n] cmp $$b[n], but you left out the more difficult-to-translate "within that". It helps to ask yourself "what does this really mean, on a level that perl could understand?", the answer, in this case, being "if the institutions are different, sort by them, otherwise, sort by course number". Which leads pretty directly to the solution proposed to you. Extending it to handle the "and possibly other values" should indicate a loop to you, something like:
      sort { my $compare; for (my $i = 0; !$compare && $i < @$a; ++$i) { $compare = $a->[$i] cmp $b->[$i]; } return $compare; }
      My apologies then, and enjoy the excellent answers from Tanktalus et al. Good on you for building your own site - I hope you are able to get to where you want to be with the help of Perlmonks!

      PS: I haven't been to MA for about 6 years, but I miss visiting Boston and the rest of New England - next time I come I'll try and pop in to your shop :)

Re: sorting an array of an arrays
by imp (Priest) on Aug 14, 2006 at 02:23 UTC
    I suspect the error you listed is occurring because there is a gap in the array that you created. As in this example:
    use Data::Dumper; my @array = (); $array[0] = [1]; $array[2] = [2]; @array = sort { $$a[0] cmp $$b[0]} @array; print Dumper \@array;
    As for the sorting algorithm, the most common approach would be something like this:
    use strict; use warnings; use Data::Dumper; my @courselist = ( ["UM", "CS 34", ], ["AC", "PHIL 13", ], ["UM", 'BIO 567', ], ["UA", 'BIO 999', ], ["UM", 'BIO 1', ], ); @courselist = sort {$$a[0] cmp $$b[0] or $$a[1] cmp $$b[1]} @courselis +t; print Dumper(\@courselist);
    As for the problem you are solving, it would probably be faster and easier to handle the sorting in a database, where the book information should probably be stored. Good luck with the project, I'll stop by your store next time I'm in Amherst :)