Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

HoH question

by cajun (Chaplain)
on Oct 06, 2005 at 05:14 UTC ( [id://497813]=perlquestion: print w/replies, xml ) Need Help??

cajun has asked for the wisdom of the Perl Monks concerning the following question:

I'm having trouble understanding why when the following code is executed, only the last item in the DATA appears in the hash.

#!/usr/bin/perl use strict; use warnings; use Data::Dumper::Simple; my @array; my %hash; while(<DATA>){ chomp; @array = split /\s+\s+/, $_; %hash = ($array[0] => {$array[1] => $array[2]}); } print Dumper (%hash); __DATA__ susan anus@delta.co.th cannot find you +r hostname jennifer r_curran@ntnu.no cannot find you +r hostname jennifer jones@bol.net.in cannot find you +r hostname jennifer millionairemaker@freshcornam.com cannot find you +r hostname tim millionairemaker@freshcornam.com cannot find you +r hostname jennifer cmayer@kareltek.fi cannot find you +r hostname jack ictiplo@tiplo.com.tw cannot find you +r hostname russ orders@koss.com Host not found clara Sandra@camrpc.com Host not found jennifer Warranty@onlogixx.com cannot find you +r hostname employment elitemate@rllformat.com cannot find you +r hostname jack JHuffman@pulsetech.net cannot find you +r hostname clara Sandra@camrpc.com Host not found susan linda@kepro.com.tw cannot find you +r hostname jobs kwillis@cors.com Host not found employment LifeShopDirect@freshcornam.com Host not found
When executed, only the last item appears in the hash.

%hash = ( 'employment' => { 'LifeShopDirect@freshcornam.com' => 'Host +not found' } );
Thanks,
Mike

Update I: I just realized that @array only had three items in it, which is of course why the HoH only has the last item in it. If there's a better way to approach this, I would appreciate comments.
Update II: Thanks very much for all the comments. I believe I have a workable solution now. Thanks very much to all. I will test each method and try to understand each one.

Considered (jbrugger): Delete, as requested by op
Unconsidered (holli): Enough Keep votes (Keep/Edit/Delete: 13/0/2)

Replies are listed 'Best First'.
Re: HoH question
by ikegami (Patriarch) on Oct 06, 2005 at 05:56 UTC
    You keep replacing what's in %hash. Don't assign to %hash, assign to elements of %hash. Also, \s+\s+ is the same as \s{2,}.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper::Simple; my %hash; while(<DATA>){ chomp; my @array = split /\s{2,}/; $hash{$array[0]} = { $array[1] => $array[2] }; } print(Dumper(%hash));

      Since the values in $array[0] are not necessarily unique, this potentially replaces the contents of $hash{$array[0]}. You need a HoAoH, or some variant thereof.

      Output (note the single entry for 'jennifer', for example):

      $VAR1 = { 'jack' => { 'JHuffman@pulsetech.net' => 'cannot find your ho +stname' }, 'jobs' => { 'kwillis@cors.com' => 'Host not found' }, 'jennifer' => { 'Warranty@onlogixx.com' => 'cannot find your + hostname' }, 'tim' => { 'millionairemaker@freshcornam.com' => 'cannot fin +d your hostname' }, 'susan' => { 'linda@kepro.com.tw' => 'cannot find your hostn +ame' }, 'russ' => { 'orders@koss.com' => 'Host not found' }, 'employment' => { 'LifeShopDirect@freshcornam.com' => 'Host +not found' }, 'clara' => { 'Sandra@camrpc.com' => 'Host not found' } };

      Thanks ikegami. Although your solution is better than mine was, it's still not exactly what I need. The results are as follows. Note jennifer, employment, clara and susan only has one 'entry'.

      %hash = ( 'clara' => { 'Sandra@camrpc.com' => 'Host not found' }, 'jack' => { 'JHuffman@pulsetech.net' => 'cannot find your ho +stname' }, 'tim' => { 'millionairemaker@freshcornam.com' => 'cannot fin +d your hostname' }, 'russ' => { 'orders@koss.com' => 'Host not found' }, 'susan' => { 'linda@kepro.com.tw' => 'cannot find your hostn +ame' }, 'employment' => { 'LifeShopDirect@freshcornam.com' => 'Host +not found' }, 'jobs' => { 'kwillis@cors.com' => 'Host not found' }, 'jennifer' => { 'Warranty@onlogixx.com' => 'cannot find your + hostname' } );
        oops, didn't notice. Change
        $hash{$array[0]} = { $array[1] => $array[2] };
        to
        $hash{$array[0]}{$array[1]} = $array[2];
        which is a shortcut for
        $hash{$array[0]} = {} if not defined $hash{$array[0]}; $hash{$array[0]}{$array[1]} = $array[2];
Re: HoH question
by bobf (Monsignor) on Oct 06, 2005 at 06:04 UTC

    It depends on how you want to access the data. A HoA keyed on the first column won't work since the values in that column are not unique. A HoH would be ok if the second key was unique within each first key (the example data has a duplicate email address but it is for two different people). Without that guarantee you could go with a HoAoA (or a HoAoH) if you wanted to look data up based on the values in the first column. If there are no lookup requirements you could just use an AoA.

    BTW, you only end up with one item in the hash because you clear it out when you assign to %hash every time through the loop.

    my @AoA; my %HoAoA; my %HoAoH; while( my $line = <DATA> ){ chomp $line; my @fields = split( /\s+\s+/, $line ); # Add an array ref (containing the data in @fields) onto the @AoA push( @AoA, [ @fields ] ); # Add an array ref (containing the last 2 elements of @fields) # onto the %HoAoA. The key in the %HoAoA is $fields[0], and # the value is an array ref. '@fields[ 1, 2 ]' is an array # slice and is shorthand for ( $fields[1], $fields[2] ) push( @{ $HoAoA{$fields[0]} }, [ @fields[ 1, 2 ] ] ); # Add a hash ref onto the %HoAoH. The key in the %HoAoH is # $fields[0], and the value is an array ref. The array # contains one or more hash refs. Each hash ref # contains the 'email' and 'result' keys. push( @{ $HoAoH{$fields[0]} }, { email => $fields[1], result => $fields[2] } ); }

    Output:

    See perldsc and perllol for more info on navigating these structures.

    HTH

Re: HoH question
by McDarren (Abbot) on Oct 06, 2005 at 05:50 UTC
    Try this:
    while(<DATA>){ chomp; my ($user, $email, $result) = split /\s+/, $_, 3; $hash{$user}{email} = $email; $hash{$user}{result} = $result; }
    (assumes that only the third column in the data will contain whitespace)

    Update: as has been pointed out below, this solution won't work because the values in the first column of the data are not unique. Sorry, I missed that :(

    --Darren
Re: HoH question
by tphyahoo (Vicar) on Oct 06, 2005 at 10:36 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://497813]
Approved by jbrugger
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (None)
    As of 2024-04-25 03:58 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found