Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Comparing Hash key with array

by packetstormer (Monk)
on Feb 02, 2012 at 16:05 UTC ( #951473=perlquestion: print w/ replies, xml ) Need Help??
packetstormer has asked for the wisdom of the Perl Monks concerning the following question:

Hello

I am having some more difficulties with hashes and arrays.
In a nutshell I have a hash with a unique ID for each key. I also have an array with the first element is always a unique ID. I am trying to iterate through the hash keys and foreach key check if it exists in the array. If it does I need to update the value of the hash (for that key) to include the values in the list after the first element (If you get me!!)
Here is what I have, and it works for one array, but as soon as start introducing multi-arrays the data gets skewed. Because the actual script pulls its data from a database it might be difficult to dump the data here but assume one hash called %ret and one array called @lines. Typically, the script will look like this:

my @line1 = ('_W9C2JJDCB','<P>This is the problem1.</P>','<P>This is r +es1</P>'); my @line2 = ('_W9C2JJDCB','<P>This is the problem2.</P>','<P>This is r +es2</P>'); my @line3 = ('_W9C2JJDCB','<P>This is the problem3.</P>','<P>This is r +es3</P>'); my @totlines; push (@totlines,\@line1); push (@totlines,\@line2); push (@totlines,\@line3); my @dir1 =('_W9C2JJDCB', '201200240', 'TEST: IGNORE', 'John Doe', 'Closed', 'HIP', 'email@email.com', 'email2@email.com', ); my %hash = ( '_W9C2JJDCB' => \@dir1); #At this point I have one hash (which may have many key/values) and on +e array which could have many array refs
# So this is what I am trying to do for my $key(keys %hash) { my $value = $hash{$key}; my @arr = @$value; foreach my $u(@totlines) { if(@$u[0] == $key) { #print "$key @arr --- @$u\n"; push (@arr,@$u); $hash{$key} = \@arr; } } } print Dumper %ret;
Now, the problem is that once the hash grows to more than one key the loops starts polluting the values with other array elements.

I appreiciate this is really hard to even explain correctly but I am hoping some will see some flaw in my logic in the "for key" loop?

EDIT: Of course an IF statement somewhere might help - added IF statement

Comment on Comparing Hash key with array
Select or Download Code
Re: Comparing Hash key with array
by Anonymous Monk on Feb 02, 2012 at 16:28 UTC

    I appreiciate this is really hard to even explain correctly but I am hoping some will see some flaw in my logic in the "for key" loop?

    It is a great thing you don't have to explain it ( How do I post a question effectively? ), simply post the correct representation of the data structure you're trying to achieve, I'll show you how to achieve it.

      OK - I will try and get a complete data dumper set of the date. In the meantime this seems to be my problem:
      foreach my $key(keys %ret) { my $value = $ret{$key}; my @arr = @$value; print "$key\n"; foreach my $u(@lines) { print "$key @$u\n"; } }
      The first FOREACH (if on it's own will print out the correct amount of keys in the hash.
      However, as soon as I add the second FOREACH (to enter the array) the keys get replicate the same amount of times the loop iterates.

        OK - I will try and get a complete data dumper set of the date.

        It isn't really necessary, simply type/copy/paste to make %hash (or %ret) look the way you want.

        In the meantime this seems to be my problem

        Thanks, but I knew this much from your original posting, I can't infer your intent -- you use == to compare strings, and you switched from %hash to %ret

      Here is the data in very simple form
      $VAR1 = { '_LFOGH4MI5' => [ '_LFOGH4MI5', '201200260', 'Software Extraction Util', 'Jane Smith', 'Closed', 'Database Query', 'email1@email.com', 'email2@email.com' ], '_W9E2B5DBZ' => [ '_W9E2B5DBZ', '201200261', 'TEST: Another test to test the testy thin +g', 'Mike Jones', 'Closed', 'HIP', 'email1@email.com', 'email2@email.com' ] }; $VAR1 = [ [ '_LFOGH4MI5', '<P>Where is the extraction utily for the console database +?.</P>', '<P>I uploaded it to our website for you to download.</P>' ], [ '_W9E2B5DBZ', '<P>Problem2</P>', '<P>Res2</P>' ], [ '_W9E2B5DBZ', '<P>Problem 1- teest</P>', '<P>Res1 - teest</P>' ], [ '_W9E2B5DBZ', '<P>Prob3</P>', '<P>res3</P>' ] ];

      So, I have a hash with the unique ID as it's key. In another part of the database is another table with problems/resolutions attached to the same unique ID. That is contained in the array (in array references). Each array has the unique ID in it first element.

      What I would like to do is start on that hash and take it's key. The run through the array and anywhere I get a match for the same ID push the rest of the array into the original value of the hash. In some cases, like above, there might be many arrays with the same ID (loads of problems/resolutions attached to the same case).

      I'd really appreciate any help, my head is set to burst!
      BTW, I have tried to lump the data together at the SQL end but datatype differences are stopping me grouping them there.

      EDIT: Hash should end up like:

      '_LFOGH4MI5' => [ '_LFOGH4MI5', '201200260', 'Software Extraction Util', 'Jane Smith', 'Closed', 'Database Query', 'email1@email.com', 'email2@email.com' '<P>Where is the extraction utily for the c +onsole database?.</P>', '<P>I uploaded it to our website for you to download.</P>' ], '_W9E2B5DBZ' => [ '_W9E2B5DBZ', '201200261', 'TEST: Another test to test the testy thin +g', 'Mike Jones', 'Closed', 'HIP', 'email1@email.com', 'email2@email.com' '<P>Problem2</P>', '<P>Res2</P>' '<P>Problem 1- teest</P>', '<P>Res1 - teest</P>' '<P>Prob3</P>', '<P>res3</P>' ] };
Re: Comparing Hash key with array
by thundergnat (Deacon) on Feb 02, 2012 at 17:19 UTC

    It is kind of difficult to figure out exactly what you are trying to do. As far as I can tell, you are trying to do something like the following. You end up with an awful lot of duplicated information though.

    If you showed an example of what your expected data structure looked like, it would be easier to help you.

    Update: I see anonymonk already had similar advice...

    use warnings; use strict; use Data::Dumper; my @totlines = map {chomp; [split /,/, $_]} <DATA>; #print Dumper \@totlines; my %hash = ( '_W9C2JJDCB' => [ '_W9C2JJDCB', '201200240', 'TEST: IGNORE', 'John Doe', 'Closed', 'HIP', 'email@email.com', 'email2@email.com', ], '_W9C2JJDCA' => [ '_W9C2JJDCA', '201200245', 'TEST: IGNORE', 'Jane Doe', 'Closed', 'HOP', 'email@imail.com', 'email2@imail.com', ], ); for my $line (@totlines) { my $key = $line->[0]; if ( defined $hash{$key} ){ push @{$hash{$key}}, @$line; } } print Dumper \%hash; __DATA__ _W9C2JJDCA,<P>This is the problem1.</P>,<P>This is res1</P> _W9C2JJDCA,<P>This is the problem2.</P>,<P>This is res2</P> _W9C2JJDCA,<P>This is the problem3.</P>,<P>This is res3</P> _W9C2JJDCB,<P>This is the problem1.</P>,<P>This is res1</P> _W9C2JJDCB,<P>This is the problem2.</P>,<P>This is res2</P> _W9C2JJDCB,<P>This is the problem3.</P>,<P>This is res3</P> _W9C2JJDCC,<P>This is the problem1.</P>,<P>This is res1</P> _W9C2JJDCC,<P>This is the problem2.</P>,<P>This is res2</P> _W9C2JJDCC,<P>This is the problem3.</P>,<P>This is res3</P>
Re: Comparing Hash key with array
by InfiniteSilence (Curate) on Feb 02, 2012 at 17:21 UTC

    Anonymous Monk already pointed out that you are comparing strings using == incorrectly. That being said, I just found the way you are doing this near incomprehensible. The code is verbose and that confounds readability. I refactored:

    use strict; use Data::Dumper; my @line1 = ('_W9C2JJDCB','<P>This is the problem1.</P>','<P>This is r +es1</P>'); my @line2 = ('_W9C2JJDCB','<P>This is the problem2.</P>','<P>This is r +es2</P>'); my @line3 = ('_W9C2JJDCB','<P>This is the problem3.</P>','<P>This is r +es3</P>'); my @line4 = ('_W8CXXXXAB','<p>hi there</p>','<p>why are you capitalizi +ng paragraph tags?</p>'); my @totlines; #push (@totlines,\@line1); #push (@totlines,\@line2); #push (@totlines,\@line3); push @totlines, \@line1, \@line2,\@line3,\@line4; my @dir1 =('_W9C2JJDCB', '201200240', 'TEST: IGNORE', 'John Doe', 'Closed', 'HIP', 'email@email.com', 'email2@email.com', ); my @dir2 = ( '_W8CXXXXAB', '2012192222', 'WHAT: HELL', 'Captain Jack', 'Wide Open', 'UNCOOL', 'you@notme.com', 'stillyou@notme.com'); my %hash = ( '_W9C2JJDCB' => \@dir1); $hash{'_W8CXXXXAB'} = \@dir2; for my $key (keys %hash){ foreach my $u (@totlines) { if($key eq $u->[0]) { #print qq|$key is equal to $u->[0]\n|; push @{$hash{$key}},@$u; } } } print Dumper \%hash;
    Makes:
    $VAR1 = { '_W9C2JJDCB' => [ '_W9C2JJDCB', '201200240', 'TEST: IGNORE', 'John Doe', 'Closed', 'HIP', 'email@email.com', 'email2@email.com', '_W9C2JJDCB', '<P>This is the problem1.</P>', '<P>This is res1</P>', '_W9C2JJDCB', '<P>This is the problem2.</P>', '<P>This is res2</P>', '_W9C2JJDCB', '<P>This is the problem3.</P>', '<P>This is res3</P>' ], '_W8CXXXXAB' => [ '_W8CXXXXAB', '2012192222', 'WHAT: HELL', 'Captain Jack', 'Wide Open', 'UNCOOL', 'you@notme.com', 'stillyou@notme.com', '_W8CXXXXAB', '<p>hi there</p>', '<p>why are you capitalizing paragraph tag +s?</p>' ] };
    I think this is what you were trying to do. I copied your @$u from the original code but as you can see from the output that copies the id over and over again. You could use a slice like this instead:
    perl -e '@a = 1..5; print @a[1..@a];'

    Celebrate Intellectual Diversity

Re: Comparing Hash key with array
by Riales (Hermit) on Feb 02, 2012 at 17:21 UTC

    Can you clarify what the resulting hash should look like?

    Are you saying that after iterating through each key of the hash, you should have:

    my @dir1 =('_W9C2JJDCB', '201200240', 'TEST: IGNORE', 'John Doe', 'Closed', 'HIP', 'email@email.com', 'email2@email.com', '<P>This is the problem1.</P>', '<P>This is res1</P>', '<P>This is the problem2.</P>', '<P>This is res2</P>', '<P>This is the problem3.</P>', '<P>This is res3</P>', );

    ?

      Yep, that is exactly what I would like to end up with.

      Sorry for the confusion I am having trouble getting my head around the data structure itself but what you said above seems to be correct. - Thanks

        This should work:

        use Data::Dumper; my @lines = ( ['_W9C2JJDCB', 'asdf1', 'zxcv1', ], ['_W9C2JJDCB', 'asdf2', 'zxcv2', ], ['_W9C2JJDCB', 'asdf3', 'zxcv3', ], ); my %hash = ( '_W9C2JJDCB' => [ '_W92CJJDCB', '201200240', 'TEST: IGNORE', 'John Doe', 'Closed', 'HIP', 'email@email.com', 'email2@email.com', ], ); foreach my $key (keys %hash) { foreach my $line (@lines) { if ($line->[0] eq $key) { shift @$line; push @{$hash{$key}}, @$line; } } } die Dumper(%hash);

        I don't know what your input data looks like, but may I suggest iterating through @lines instead of keys %hash in the outer loop? This way, you can use the hash's look-up to check if there's a match. Your way is better if there's a massive amount of data in @lines that doesn't have a match in %hash though. Let me know if you'd like some help with the other way!

        EDIT: I TAKE BACK WHAT I SAID

        You should definitely iterate through @lines first no matter what; it's far more efficient:

        foreach my $line (@lines) { my $key = shift @$line; if (exists($hash{$key})) { push @{$hash{$key}}, @$line; } }

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (9)
As of 2014-12-28 02:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (178 votes), past polls