perl.cvs.perlfaq
[Top] [All Lists]

[svn:perlfaq] r11388 - perlfaq/trunk

Subject: [svn:perlfaq] r11388 - perlfaq/trunk
From: comdog@xxxxxxxxxxxx
Date: Sat, 7 Jun 2008 16:46:58 -0700 (PDT)
Newsgroups: perl.cvs.perlfaq

Author: comdog
Date: Sat Jun  7 16:46:57 2008
New Revision: 11388

Modified:
   perlfaq/trunk/perlfaq4.pod

Log:
* perlfaq4:

* How can I tell whether a certain element is contained in a list or array?
        + added smart matching example
        
* How do I test whether two arrays or hashes are equal?
        + added smart matching example
        
* How do I merge two hashes?
        + new question suggested by Shlomi Fish



Modified: perlfaq/trunk/perlfaq4.pod
==============================================================================
--- perlfaq/trunk/perlfaq4.pod  (original)
+++ perlfaq/trunk/perlfaq4.pod  Sat Jun  7 16:46:57 2008
@@ -1302,16 +1302,32 @@
 
 =head2 How can I tell whether a certain element is contained in a list or 
array?
 
-(portions of this answer contributed by Anno Siegel)
+(portions of this answer contributed by Anno Siegel and brian d foy)
 
 Hearing the word "in" is an I<in>dication that you probably should have
 used a hash, not a list or array, to store your data.  Hashes are
 designed to answer this question quickly and efficiently.  Arrays aren't.
 
-That being said, there are several ways to approach this.  If you
+That being said, there are several ways to approach this.  In Perl 5.10
+and later, you can use the smart match operator to check that an item is
+contained in an array or a hash:
+
+       use 5.010;
+       
+       if( $item ~~ @array ) 
+               { 
+               say "The array contains $item"
+               }
+       
+       if( $item ~~ %hash )
+               { 
+               say "The hash contains $item"
+               }
+
+With earlier versions of Perl, you have to do a bit more work. If you
 are going to make this query many times over arbitrary string values,
 the fastest way is probably to invert the original array and maintain a
-hash whose keys are the first array's values.
+hash whose keys are the first array's values:
 
        @blues = qw/azure cerulean teal turquoise lapis-lazuli/;
        %is_blue = ();
@@ -1386,6 +1402,21 @@
 
 =head2 How do I test whether two arrays or hashes are equal?
 
+With Perl 5.10 and later, the smart match operator can give you the answer
+with the least amount of work:
+
+       use 5.010;
+       
+       if( @array1 ~~ @array2 )
+               {
+               say "The arrays are the same";
+               }
+               
+       if( %hash1 ~~ %hash2 ) # doesn't check values!
+               {
+               say "The hash keys are the same";
+               }
+               
 The following code works for single-level arrays.  It uses a
 stringwise comparison, and does not distinguish defined versus
 undefined empty strings.  Modify if you have other needs.
@@ -1939,6 +1970,62 @@
 the iterator and mess up your processing. See the C<each> entry in
 L<perlfunc> for more details.
 
+=head2 How do I merge two hashes?
+X<hash> X<merge> X<slice, hash>
+
+(contributed by brian d foy)
+
+Before you decide to merge two hashes, you have to decide what to do
+if both hashes contain keys that are the same and if you want to leave
+the original hashes as they were.
+
+If you want to preserve the original hashes, copy one hash (<%hash1>)
+to a new hash (C<%new_hash>), then add the keys from the other hash
+(C<%hash2> to the new hash. Checking that the key already exists in
+C<%new_hash> gives you a chance to decide what to do with the
+duplicates:
+
+       my %new_hash = %hash1; # make a copy; leave %hash1 alone
+       
+       foreach my $key2 ( keys %hash2 )
+               {
+               if( exists $new_hash{$key2} )
+                       {
+                       warn "Key [$key2] is in both hashes!";
+                       # handle the duplicate (perhaps only warning)
+                       ...
+                       next;
+                       }
+               else
+                       {
+                       $new_hash{$key2} = $hash2{$key2};
+                       }                       
+               }
+
+If you don't want to create a new hash, you can still use this looping
+technique; just change the C<%new_hash> to C<%hash1>. 
+
+       foreach my $key2 ( keys %hash2 )
+               {
+               if( exists $hash1{$key2} )
+                       {
+                       warn "Key [$key2] is in both hashes!";
+                       # handle the duplicate (perhaps only warning)
+                       ...
+                       next;
+                       }
+               else
+                       {
+                       $hash1{$key2} = $hash2{$key2};
+                       }                       
+               }
+
+If you don't care that one hash overwrites keys and values from the other, you
+could just use a hash slice to add one hash to another. In this case, values 
+from C<%hash2> replace values from C<%hash1> when they have keys in common:
+
+       @hash1{ keys %hash2 } = values %hash2;
+
 =head2 What happens if I add or remove keys from a hash while iterating over 
it?
 
 (contributed by brian d foy)

<Prev in Thread] Current Thread [Next in Thread>
  • [svn:perlfaq] r11388 - perlfaq/trunk, comdog <=