If there are no duplicates, you can do this:
my %norm = reverse %dem;
Of course in general there are, so you have to be more careful:
\nmy %norm;\nwhile( my ($key, $val) = each %den) {\npush @{ $norm{$val} }, $key;\n}\n
Voila!
The problem in your code is that you keep on switching between hashes and arrays, and references to hashes or arrays. You can't do that in Perl. Also you have to always look at how lists expand. So, for instance, you write:
\nmy %norm =\n{\n"a" => (),\n"b" => (),\n"c" => ()\n};\n
all of those ()s get expanded to nothing, Perl actually sees,
\nmy %norm =\n{\n"a",\n"b",\n"c"\n};\n
which is
\nmy %norm =\n{\n"a" => "b",\n"c" => undef,\n};\n
and - even worse - {} constructs a reference to a hash so that is assigned as the key of a hash. So you wind up actually with something like:
\nmy %norm = ('HASH(0x815dba8) => undef);\n
(The address of the hash will vary - but it doesn't matter since you didn't keep a reference to it so it got unallocated.)
In the same way if you say:
\nmy @list = $norm{$val};\n
what you get is an array with a reference to an array in it. (Actually with undef rather than a reference to an array since %norm didn't have what you expect.) You then append to @list in the next line, but that doesn't do anything because then @list gets discarded.
So your code is going to wind up with %norm having one unexpected key and no values.
For playing around with this kind of thing, I
strongly recommend using Data::Dumper. Something like this would have helped you see what is happening:
\nuse Data::Dumper;\nprint Dumper(\\%norm);\n
Cheers,
Ben
PS For a lot of problems like this, the
Perl Cookbook has useful recipies. I highly recommend using it as a reference until your brain starts "getting" how Perl is supposed to work.
EDIT I simplified the real solution slightly by getting rid of a superfluous my.
Edited by
ben_tilly
Oct. 7, 2004, 05:31:13 PM EDT
Simple solution
If there are no duplicates, you can do this:
my %norm = reverse %dem;
Of course in general there are, so you have to be more careful:
my %norm;
while((my $key,my $val) = each %den) {
push @{ $norm{$val} }, $key;
}
Voila!
The problem in your code is that you keep on switching between hashes and arrays, and references to hashes or arrays. You can't do that in Perl. Also you have to always look at how lists expand. So, for instance, you write:
my %norm =
{
"a" => (),
"b" => (),
"c" => ()
};
all of those ()s get expanded to nothing, Perl actually sees,
my %norm =
{
"a",
"b",
"c"
};
which is
my %norm =
{
"a" => "b",
"c" => undef,
};
and - even worse - {} constructs a reference to a hash so that is assigned as the key of a hash. So you wind up actually with something like:
my %norm = ('HASH(0x815dba8) => undef);
(The address of the hash will vary - but it doesn't matter since you didn't keep a reference to it so it got unallocated.)
In the same way if you say:
my @list = $norm{$val};
what you get is an array with a reference to an array in it. (Actually with undef rather than a reference to an array since %norm didn't have what you expect.) You then append to @list in the next line, but that doesn't do anything because then @list gets discarded.
So your code is going to wind up with %norm having one unexpected key and no values.
For playing around with this kind of thing, I
strongly recommend using Data::Dumper. Something like this would have helped you see what is happening:
use Data::Dumper;
print Dumper(\%norm);
Cheers,
Ben
PS For a lot of problems like this, the
Perl Cookbook has useful recipies. I highly recommend using it as a reference until your brain starts "getting" how Perl is supposed to work.
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)