IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New 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:
\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.
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)
Collapse 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)
New Bleh.
Perl never seems to do what I expect it to do...
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New That's because you approached it wrong
I'm serious.

Perl was designed as a "better shell, with a few things integrated in" and all of the "BTW its now a real programming language" stuff was later shoehorned on top. So if you use it as a "better shell, with a few things integrated in", it tends to work out well and it doesn't take you long to train your intuition about what Perl's "grammar" looks like. And once your intuition is trained by that, the real programming stuff fits in surprisingly well.

But if you approach it as a real programming language right off of the bat, you're going to keep tripping over the features that were prominently placed because that's what it has been optimized for.

Cheers,
Ben
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)
New I'm gradually warming up to it
Right now I'm doing a lot of shell and wish I could use Perl for some things. Will wonders never cease?
-drl
New That should be in the man page.
Or something.

Scott's comment echoes my own problem(s) with Perl and your reply is extremely astute.

Wade, who has several times made the mistake of approaching Perl incorrectly.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New Is this a sort of typecasting?
push @{ $norm{$val} }, $key;

Specifically the @{ }

I ask because later on when trying to print out the list I end up needing to say

for my $item ( @{ $norm{$key} } ) { print $item; }

where I had to add the @{ } to get something different from <ARRAY0xCRAP> from printing and see the elements again.

I expected $norm{$key} to be a list but it seems to be more like some kind of wrapper.



That was lovely cheese.

     --Wallace, The Wrong Trousers
New It's a reference
New Sort of
What's actually happening is that $norm{$val} is the reference to the array. Decorating it by @{ $norm{$val} } accesses the array.

It's the same kind of dereferencing that you go through in C to get at a struct that you have a pointer to.

You could also write ${ $norm{$val} }[3] to access the 4'th element. Or use the syntactic shortcut $norm{$val}[3].

As for your expectation, you're tripping over the fact that Perl is a list-oriented language. There is no such thing as a straight list in Perl. Nothing will act "like a list". Instead in a lot of places things will be interpreted as lists and will do something interesting.

Cheers,
Ben
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)
New Interesting....

my %norm =
{
"a" => (),
"b" => (),
"c" => ()
};


all of those ()s get expanded to nothing, Perl actually sees,

my %norm =
{
"a",
"b",
"c"


Just to refresh my memory, the key is that those () are effectively nothing. If he had used a reference to an empty array, that (part) would work, no?

so, one solution would be

@empty_array;

my %norm =
{
"a" => \\@empty_array;
"b" => \\@empty_array;
"c" => \\@empty_array;
}
New The solution would have its own problems
In particular, now all values are the same, and so updating one updates them all. You were looking for this:
\nmy %norm =\n  (\n  "a" => [],\n  "b" => [],\n  "c" => [],\n  );\n

(note that you still need to fix the () vs {} issue.)

But in any case the right solution is to assume that %norm needs no initialization at all. Perl will autovivify it to be The Right Thing.

In fact that's kind of the point of having all the syntax - Perl has enough clues to be able to figure out The Right Thing and do it for you. For instance you can write:
\n  push @{ my $norm{$key} }, $value;\n

and if need be it will realize, "There is no value in %norm for $key - I need to create one and clearly it should be an anonymous array." In, say, Ruby you'd have to write two lines - one to make sure that the array was there and another to push something onto it.

(Whether the syntax is worth that benefit I'll not debate. I'm trying to explain Perl, not advocate it.)

Cheers,
Ben
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)
New <bow> thank you.
     Perl frustrations - (tuberculosis) - (45)
         Simple solution - (ben_tilly) - (10)
             Bleh. - (admin) - (3)
                 That's because you approached it wrong - (ben_tilly) - (2)
                     I'm gradually warming up to it - (deSitter)
                     That should be in the man page. - (static)
             Is this a sort of typecasting? - (tuberculosis) - (2)
                 It's a reference -NT - (Simon_Jester)
                 Sort of - (ben_tilly)
             Interesting.... - (Simon_Jester) - (2)
                 The solution would have its own problems - (ben_tilly) - (1)
                     <bow> thank you. -NT - (Simon_Jester)
         THank you for stepping on this rake - (Arkadiy) - (33)
             He was overcomplicating it - (ben_tilly) - (32)
                 Well, maybe - (tuberculosis) - (17)
                     Agreed - (ben_tilly) - (16)
                         Agree its a mistake - (tuberculosis) - (15)
                             Same here. - (admin)
                             Right - (ben_tilly)
                             Shame about the inertia. Python's design is "least surprise" - (FuManChu) - (12)
                                 When I started with Perl... - (ben_tilly) - (11)
                                     On Perl 6 - (pwhysall) - (3)
                                         Re: On Perl 6 - (Yendor)
                                         I had a nice response to this typed up - (ben_tilly) - (1)
                                             Many thanks for that - (pwhysall)
                                     We're having a little brown bag on Ruby - (tuberculosis) - (4)
                                         Re: We're having a little brown bag on Ruby - (JimWeirich) - (3)
                                             Shhh! Anonymous Todd works at some other... - (CRConrad)
                                             I might have been there - (tuberculosis) - (1)
                                                 Re: I might have been there - (JimWeirich)
                                     Re: strict -- have you seen pychecker? - (FuManChu) - (1)
                                         No I hadn't, thanks - (ben_tilly)
                 BTW Arkadiy, I'm still waiting for a response - (ben_tilly) - (13)
                     I am not saying it's shorter in C... - (Arkadiy) - (10)
                         And now for my real comment - (ben_tilly) - (2)
                             May be it's a hindsight thing - (Arkadiy) - (1)
                                 It could be many things - (ben_tilly)
                         I don't know - multimap - (Simon_Jester) - (6)
                             Re: I don't know - multimap - (Arkadiy) - (5)
                                 Why the worry about efficiency? - (ben_tilly) - (4)
                                     I worry about efficiency - (Arkadiy) - (1)
                                         Ah - (ben_tilly)
                                     C vs Perl - efficiency - untrue for me - (broomberg) - (1)
                                         Point - but you may want to rebenchmark - (ben_tilly)
                     Here's a smalltalk version - (tuberculosis) - (1)
                         Yes, think of a reference as a pointer - (ben_tilly)

At least as intelligible as your X-Man666.JPG monologues.
83 ms