Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: Need advice on checking two hashes values and keys

by aaron_baugher (Curate)
on Jun 03, 2015 at 22:18 UTC ( [id://1129006]=note: print w/replies, xml ) Need Help??


in reply to Need advice on checking two hashes values and keys

Your first loop is fine; it reads lines from the first file and puts them in a hash as keys and values. Your second loop is kind of a mess. You have a few choices:

  1. On each line, find its key in the hash and go ahead and print the key (Italian), the value already in the hash (Spanish), and the value found in the current file (French).
  2. On each line, save the key and value into a new hash. Then after the second loop, have a third loop that goes through one of the hashes and prints out the keys and their values from each hash.
  3. Instead of saving the values in two hashes as simple scalars, save them in a single hash as a two-element array. So the hash would be structured like this:
    $hash = ( uno => [ 'uno','un' ], due => [ 'dos','due' ], tre => [ 'tres','tris' ], # and so on );
    This would mean changing your first loop so that it stores keys and values as $hash{$key}[0] and those from the second loop as $hash{$key}[1].

A problem with solutions #2 and #3 is that a hash is not ordered, so when you loop through the hash to print out the lines, they will not be in the order you want. To fix that, you would have to use an array of arrays instead of a hash, or keep a separate array of the keys to hold their order, or use a module that provides an ordered hash. If you use solution #1, you'll be printing them out in the same order you find them in the second file, which appears to be what you want.

Aaron B.
Available for small or large Perl jobs and *nix system administration; see my home node.

Replies are listed 'Best First'.
Re^2: Need advice on checking two hashes values and keys
by perlynewby (Scribe) on Jun 03, 2015 at 22:54 UTC

    cool. nice explanation and advice on attack.

    your number 3 seems to be a little more advance where I am but I think I want to use this method. I see alot of potential here. although, the numerical ordering is nice, I think putting it in this form will make me practice more difficult hashes then, after, I can practice on order.

    so... more questions will follow on this 3rd type of exercise...thanks all for the help and advice.

      You're welcome. One way of doing it with a hash of arrays while maintaining the original order would be to save the line number in which you find each key together with its value. So your hash after the first loop would look like this:

      $hash = ( uno => [ 1, 'uno' ], due => [ 2, 'dos' ], tre => [ 3, 'tres' ], # and so on );

      Then after the second loop it would look like this:

      $hash = ( uno => [ 1, 'uno','un' ], due => [ 2, 'dos','due' ], tre => [ 3, 'tres','tris' ], # and so on );

      Then you'd need to learn how to sort the hash on the first element in each sub-array so that you can print them out in order. If you want to try that, then inside your first loop, you can get the line number to go with each key/value pair from the special $. variable.

      Aaron B.
      Available for small or large Perl jobs and *nix system administration; see my home node.

Re^2: Need advice on checking two hashes values and keys
by perlynewby (Scribe) on Jun 04, 2015 at 20:53 UTC

    I appreciate all the advice and examples to manipulate hash, hash table, code improvement and will do all of these with your help.

    should I create a new thread for each example or stick with this thread? maybe some other newbie can learn from it.

    Ok, I've been playing with hash ref to get a 2 element hash.

    hasn't worked yet. will you provide some instruction/teach/explain the error I did on hash ref? error it gave me.

    Can't use string ("dos") as an ARRAY ref while "strict refs" in use at C:\Users\Alberto\Documents\NetBeansProjects\PerlProject\Perl Essentials\hash_ref_6_4.pl line 34, <$in1> line 1.

    use strict; use warnings; use Data::Dump qw(dump); my %hash; #my file handles UNTIL I figure how to install the Inline::File module + to netbeans IDE open my $in, '<',"./test_data.txt" or die ("can't open the file:$!\n") +; open my $in1,'<',"./test_data1.txt" or die ("can't open file : $!\n"); open my $out ,'>' ,"./test_data_out.txt" or die "can't open the file f +or write:$!\n"; open my $out1 ,'>',"./test_data_out1_no_match.txt" or die "can't open +file for write:$!\n"; #creating hash while (<$in>){ chomp; my ($key,$value)= split(/\s*=\s*/); #conto di spazio prima o dopo +la parola $hash{$key}=$value; } close $in; #using the first hash while (<$in1>){ chomp; my($key,$value)=split/\s*=\s*/ ; #push the value to existing hash as to get reference if key exists # %hash =( It => [Spa Fre]) #using one hash as per Ken code suggestion?? push @{$hash{$key}},$value if $hash{$key}; #non so come funzio +na "push" print $out dump (\%hash); } close $in1; close $out; close $out1;

      (I'd suggest that you keep posting to this thread as long as you're working on the same problem, unless people stop responding to it.)

      Ok, let's say you want to create a hash of two-element arrays, with the hash keys being the Italian numbers, each one pointing to a reference to a two-element array holding the Spanish and French numbers, in that order. Then as you're going through the first loop (Italian = Spanish), you need to insert the Spanish numbers as the first element of an array rather than a simple value:

      $hash{$italian} = [ $spanish ];

      The square brackets return a reference to an array, which is a scalar that can be stored as a value in the hash. So now it looks like this, with references to one-element arrays as the values:

      $hash = ( uno => [ 'uno' ], due => [ 'dos' ], # and so on );

      Then in the second loop, you need to add the French numbers to the arrays corresponding to their matching Italian hash keys. There are two ways you could do this:

      # by assigning directly to the second element of the sub-array $hash{$italian}[1] = $french; # or by dereferencing the sub-array pointed to by the hash value # and pushing the new value onto the end of that array push @{$hash{$italian}}, $french; # Either way, you'll end up with: $hash = ( uno => [ 'uno','un' ], due => [ 'dos','deux' ], # and so on );

      Then when you're ready to print them out, you loop through the keys of the hash, printing the key and the elements of the sub-array as you wish:

      for my $key (keys %hash){ print $key, ' => ', join ' , ', @{$hash{$key}}; # dereference sub-ar +ray print "\n"; }

      The trick is keeping track of what level of the structure you're dealing with, and getting the sigils (and arrows, if necessary) right for pointing to the right things, whether values or references.

      Aaron B.
      Available for small or large Perl jobs and *nix system administration; see my home node.

        cool. the square brackets was the correct method to do a ref to array...missed it although I read about it last night.thanks.

        several questions

        PROBLEM: the array seem to list of all of the numbers found in both files. I want to only print out the numbers that are fund on BOTH in one file then the numeri not found in the other into another file

        my IF check doesn't seem to work?

        push @{$hash{$key}},$value if $hash{$key}; #non so come funziona "push"

        how is this piece of code work? I don't understand the "[1]", I think +it's a matrix , is it placement spot??
        $hash{$italian}[1] = $french;

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (3)
As of 2024-04-25 19:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found