What type of array would work beter
am 21.04.2006 19:05:33 von unknownPost removed (X-No-Archive: yes)
Post removed (X-No-Archive: yes)
Terry wrote:
> Occasionally I run into a choice where I can either store data into multiple
> hashes, each using the same key so I can tie the information together, or using
> a multi-dimensional hash.
>
> The former is pretty straight forward, and tend to use that more. If sorting
> wasn't such a pain
If you think sorting is a pain in Perl, you don't understand sort() in
Perl. If you have a specific question about it, we could probably help
you to understand better.
> I'd pro baby make use of the other more often. Are there
> significant performance benefits or other improvements that I should consider
> and use multi-dimensional arrays instead?
I can't see how or why you'd transform multiple hashes all using the
same keys into a multi-dimentional array. A multi-dimensional hash, on
the other hand, makes vastly more sense.
The single hash keeps all your data together in one variable. No need
to declare and use repeated variables. No need to worry about typoing
the key name in one variable but not the others, etc.
Basically, I have no idea what benefit you think you're gaining from
the multiple single-dimensional hashes. If you could explain what that
is, I can probably respond with a better answer.
Paul Lalli
Post removed (X-No-Archive: yes)
Terry wrote:
> Thanks for the reply Paul, I'll try to clarify. I think the sorting examples for
> multi-dimensional arrays I've seen in the O'Reilly Perl book just aren't sinking
> in.
>
> I understand your basic sort on a key and/or its value and using "cmp" or "<=>"
> for an alph or numeric sort. Maybe I'm just trying to do too many sort options
> on one foreach loop and need to break it up more?
No, I think you're just not really understanding what the sort block
does, other than you know that it uses 'cmp' for alphabetic and '<=>'
for numeric.
> As an example if I had hundreds of users that I got information for and stored
> in a multi-dimensional array ...
>
> while(
> {
> $Traits{$user}{$height};
> $Traits{$user}{$weight};
> }
What is this? This is not storing anything. These are two scalars
used in void context. What are $height and $weight? I'm willing to
bet you actually meant something along these lines:
while (
my ($user, $h, $w) = split;
$Traits{$user}{height} = $h;
$Traits{$user}{weight} = $w;
}
but without real code, there's no way of knowing what you are actually
trying to do.
> How do I sort users by weight, but still print out the $user and $height
> information?
Assuming my loop above:
#the next three lines can really be done in one, but I'm
#expanding for clarity's sake.
my @users = keys %Traits
my @sorted_users = sort { $Traits{$a}{weight} <=> $Traits{$b}{weight}
@users;
for my $user (@sorted_users) {
print "$user: W: $Traits{$user}{weight}; H:
$Traits{$user}{height}\n";
}
> With multiple arrays I could store them as
>
> while(
> {
> $Height{$user};
> $Weight{$user};
> }
And again, this isn't storing anything. I don't know what you're
actually trying to do.
> ..then sort on whichever hash I needed. I could then look up the other hash(es)
> using the unique key. I understand the benefits you mentioned of having a single
> array, but the sorting is just confusing as hell with those.
Again, it's not confusing if you actually understand what sort is
doing. Sort takes a list of items (in this case, the keys of the big
hash, which are users). It will repeatedly grab two of these items,
and run a comparison. To run this comparison, it calls one of the
items $a, and the other $b. All you have to do is tell Perl by what
means you want this comparison done. To do that, you write a very
small subroutine. In this subroutine, you have access to the $a and $b
that sort() is looking at. You compare $a and $b however you want, and
if you determine that $a should come before $b, you return -1. If you
determine that $a should come after $b, you return 1. And if you
determine it doesn't matter which comes first, you return 0. So that
subroutine in this case would look like this:
sub by_weight {
# sort() has given us $a and $b
#if a's weight is less than b's
if ($Traits{$a}{weight} < $Traits{$b}{weight}) {
# put $a first
return -1;
}
#else, if a's weight is more than b's
elsif ($Traits{$a}{weight} > $Traits{$b}{weight}) {
#put $b first
return 1;
}
#else, their weights are the same
else {
#it doesn't matter which is first
return 0;
}
}
That if-elsif-else statement is such a standard piece of algorithm,
that Perl contains a shortcut: The <=> operator. This operator
compares its left value and right value. If the left one is less, it
returns -1. If the left one is greater, it returns 1. And if they're
equal, it returns 0. So that entire if-elsif-else block can be reduced
to:
return $Traits{$a}{weight} <=> $Traits{$b}{weight};
Now, we use this subroutine in our sort:
my @sorted_users = sort by_weight @users;
Except that when the sort subroutine is so simple like this, there's no
reason to actually bother declaring the subroutine separately - we can
just use it "inline":
my @sorted_users = sort { $Traits{$a}{weight} <=> $Traits{$b}{weight}
} @users;
The fact remains, however, that the items being compared and sorted are
still keys to the hash %Traits, so we can still use them to get
whatever values from the hash we want, including the height, as we did
above.
I hope this helps clarify a little.
Paul Lalli
In article
> On 21 Apr 2006 11:22:29 -0700, Paul Lalli wrote...
> >
> >Terry wrote:
> >> Occasionally I run into a choice where I can either store data into
> >> multiple
> >>hashes, each using the same key so I can tie the information together, or
> >>using
> >> a multi-dimensional hash.
> >>
> >> The former is pretty straight forward, and tend to use that more. If
> >> sorting
> >> wasn't such a pain
[explanation of using multi-dimensional arrays snipped]
>
> As an example if I had hundreds of users that I got information for and stored
> in a multi-dimensional array ...
>
> while(
> {
> $Traits{$user}{$height};
> $Traits{$user}{$weight};
> }
There is no multi-dimensional array shown there. There is a nested
hash-of-hashes shown, but you are not setting a value of anything, and
you don't show how you parse the input lines.
You can use a hash-of-hashes this way:
#!/usr/local/bin/perl
#
use strict;
use warnings;
my %traits;
while() {
my( $name, $key, $value ) = split;
$traits{$name}{$key} = $value;
}
for my $key ( sort { $traits{$a}{weight} <=> $traits{$b}{weight} }
keys %traits ) {
print "$key: $traits{$key}{weight} $traits{$key}{height}\n";
}
__DATA__
bob weight 170
bob height 6.2
alice weight 120
alice height 5.4
carol weight 340
carol height 4.8
Output:
alice: 120 5.4
bob: 170 6.2
carol: 340 4.8