develooper Front page | perl.beginners | Postings from May 2010

Re: Inverting a hash

Thread Previous | Thread Next
From:
Shawn H Corey
Date:
May 9, 2010 07:50
Subject:
Re: Inverting a hash
Message ID:
4BE6CBC2.5020207@gmail.com
Harry Putnam wrote:
> I have an example from Shawn C. from another thread, presented here
> out of context.  The code does just what he meant it to do.
> It inverts a hash.
> 
> I'm trying to understand what is going on inside the sub function
> `invert()'.
> 
> -------        ---------       ---=---       ---------      -------- 
> 
> my %hash  = (
>            './b/fb'        => 'fb',
>            './b/c/fd'      => 'fd',
>            './b/l/c/f2'    => 'f2',
>            './b/g/f/r/fc'  => 'fc',
>            './b/g/h/r/fb'  => 'fb'
> 
>        );
> 
> ## %hash is sent to an inversion sub function
>   my %inv_hash = invert( \%hash );
> 
> sub invert {
>   my $h = shift @_;
>   my %inv = ();
> 
>   while( my ( $k, $v ) = each %{ $h } ){
>     push @{ $inv{$v} }, $k;
>   }
>   return %inv;
> }
> 
> -------        ---------       ---=---       ---------      -------- 
> 
> What is actually being sent at 
>   my %inverse_hash = invert( \%hash );

A reference to the hash %hash is being sent.

> 
> Inside the sub function:
>  incoming data is seen as array (@_)
>  What happened to the hash?  Is it flattened or what?

It's still there.  The array @_ has a reference to the hash as its first 
value.

> 
> What is actually being shifted off here
>   my $h = shift @_;  (Just one element?)

The reference is stored in the variable $h.

> 
> Here it appears $h is expected to have two parts.
> So apparently sending \%hash to this sub function has flattened it
> into an array where each elements is made up of the Key and value 
> of the former array...
> 
>   while( my ( $k, $v ) = each %{ $h } ){

The function each only works on hashes.  $h is dereference with %{ $h }

See `perldoc -f each`

> 
> It appears above that $h has all the former parts of the hash
> else how can it be looped?
> 
> but at  `my $h = shift @_;'
> It looks like only one is shifted.

Yes, only one argument is sent to the function, the reference to the hash.

> 
> Then at:
> 
>   push @{ $inv{$v} }, $k;
> 
> It appears the parts to an array are again flattened into
> an array

If $inv{$v} does not exists, then this statement create an empty, 
anonymous array and pushes the value of $k onto it.  If $inv{$v} exists, 
it must be a reference to an array or this will cause a fatal error.

> 
> Then here:
>     return %inv;
> 
> It magically becomes a hash again only upside down.
> and of course same name keys are zapped.
> 
>   %inv_hash is now:
>       'fc'  => './b/g/f/r/fc'
>       'f2'  => './b/l/c/f2'
>       'fb'  => './b/fb'  (might be './b/g/h/r/fb'. One was deleted)
>       'fd'  => './b/c/fd'
>   
>   or seen through Data::Dumper:
> 
>    Key fc | value ARRAY(0x8bb29c0)
>    Key f2 | value ARRAY(0x8bb2a60)
>    Key fb | value ARRAY(0x8bb29f0)
>    Key fd | value ARRAY(0x8bb2a20)
> 
> There is a lot happening in there... but I'm not following how it
> happens. 
> 
> 

   my %inv_hash = invert( \%hash );
   print '%inv_hash: ', Dumper \%inv_hash;

This will output:

%inv_hash: $VAR1 = {
   'f2' => [
     './b/l/c/f2'
   ],
   'fb' => [
     './b/fb',
     './b/g/h/r/fb'
   ],
   'fc' => [
     './b/g/f/r/fc'
   ],
   'fd' => [
     './b/c/fd'
   ]
};

Note that both values for fb are preserved.


-- 
Just my 0.00000002 million dollars worth,
   Shawn

Programming is as much about organization and communication
as it is about coding.

I like Perl; it's the only language where you can bless your
thingy.

Eliminate software piracy:  use only FLOSS.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About