arbitrary sorting...

Tkil tkil at scrye.com
Thu Jul 18 18:33:27 CDT 2002


I wrote:

> if you know that @foo is a subset of @bar (that is, there are no
> elements of @foo that are not also in @bar), then you can do:
> 
> | my %bar_score = do
> | {
> |     my $i = 0;
> |     map { $_ => ++i } reverse @bar;
                    ^^^
> | };
> | my @foo_by_bar = sort { $bar_score{$a} <=> $bar_score{$b} } @foo
> 

Sigh.  The things I see when I'm awake.   That should be ++$i, of
course.

One way to avoid the reverse is to start with a higher score, and
count down.  (Or start with zero and go negative -- same difference.)

So, I'd probably really do it more like this:

| #!/usr/bin/perl -w
| 
| use strict;
| 
| my @bar = qw( porsche bmw audi buick ford chevy subaru jaguar
|               horse cow dog cat pig
|               sushi hamburger fish-n-chips burrito
|               pear apple mango banana strawberry grapefruit orange );
| 
| my @foo = qw( banana porsche subaru apple cat oddball buick cow mango );
| 
| my @foo_by_bar = do
| {
|     my $i = 0;
|     my %s = map { $_ => ++$i } @bar;
|     if (my @missing = grep !exists($s{$_}), @foo)
|     {
|         warn "not in bar: @missing\n";
|         foreach (@missing) { $s{$_} = ++$i; }
|     }
|     sort { $s{$a} <=> $s{$b} } @foo;
| };
| 
| print "foo:    @foo\n",
|       "by bar: @foo_by_bar\n";

If you are into micro-optimizations, it might be amusing to compare
the "map" scoring with something like:

| my %s;
| @s{@bar} = 0 .. $#bar;

Which might be a bit faster.  I wouldn't make any wagers one way or
another, though.  Heh.  You'll have to adjust the backup scoring, too,
yielding:

| my @foo_by_bar = do
| {
|     my %s;
|     @s{@bar} = 0 .. $#bar;
|     if (my @missing = grep !exists($s{$_}), @foo)
|     {
|         warn "not in bar: @missing\n";
|         @s{@missing} = @bar .. @bar+ at missing-1;
|     }
|     sort { $s{$a} <=> $s{$b} } @foo;
| };

Anyway.  Happy nugget polishing,
t.
TIMTOWTDI



More information about the Pdx-pm-list mailing list