* How can I tell whether a certain element is contained in a list or
array?
   + Anno updated this answer with pointers to List::Util

* How can I use a reference as a hash key?
   + I updated the answer to explain why you shouldn't.
   + If people have other favorite modules to handle this sort
   of thing, let me know so I can add them to the answer.



Index: perlfaq4.pod
===================================================================
RCS file: /cvs/public/perlfaq/perlfaq4.pod,v
retrieving revision 1.67
diff -u -d -r1.67 perlfaq4.pod
--- perlfaq4.pod  10 Aug 2005 15:55:49 -0000 1.67
+++ perlfaq4.pod  10 Oct 2005 19:03:23 -0000
@@ -1212,6 +1212,8 @@
 
 =head2 How can I tell whether a certain element is contained in a list
or array?
 
+(portions of this answer contributed by Anno Siegel)
+
 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.
@@ -1247,28 +1249,35 @@
 
 Now check whether C<vec($read,$n,1)> is true for some C<$n>.
 
-Please do not use
+These methods guarantee fast individual tests but require a
re-organization
+of the original list or array.  They only pay off if you have to test
+multiple values against the same array.
 
-    ($is_there) = grep $_ eq $whatever, @array;
+If you are testing only once, the standard module List::Util exports
+the function C<first> for this purpose.  It works by stopping once it
+finds the element. It's written in C for speed, and its Perl equivalant
+looks like this subroutine:
 
-or worse yet
+  sub first (&@) {
+     my $code = shift;
+     foreach (@_) {
+        return $_ if &{$code}();
+     }
+     undef;
+  }
 
-    ($is_there) = grep /$whatever/, @array;
+If speed is of little concern, the common idiom use grep in scalar
context
+(which returns the number of items that passed its condition) to
traverse the
+entire list. This does have the benefit of telling you how many
matches it
+found, though.
 
-These are slow (checks every element even if the first matches),
-inefficient (same reason), and potentially buggy (what if there are
-regex characters in $whatever?).  If you're only testing once, then
-use:
+  my $is_there = grep $_ eq $whatever, @array;
 
-    $is_there = 0;
-    foreach $elt (@array) {
-  if ($elt eq $elt_to_find) {
-      $is_there = 1;
-      last;
-  }
-    }
-    if ($is_there) { ... }
+If you want to actually extract the matching elements, simply use grep
in
+list context.
 
+  my @matches = grep $_ eq $whatever, @array;
+  
 =head2 How do I compute the difference of two arrays?  How do I
compute the intersection of two arrays?
 
 Use a hash.  Here's code to do both and more.  It assumes that
@@ -1982,8 +1991,18 @@
 
 =head2 How can I use a reference as a hash key?
 
-You can't do this directly, but you could use the standard Tie::RefHash
-module distributed with Perl.
+(contributed by brian d foy)
+
+Hash keys are strings, so you can't really use a reference as the key.
+When you try to do that, perl turns the reference into its stringified
+form (for instance, C<HASH(0xDEADBEEF)>). From there you can't get back
+the reference from the stringified form, at least without doing some
+extra work on your own. Also remember that hash keys must be unique,
but
+two different variables can store the same reference (and those
variables
+can change later).
+
+The Tie::RefHash module, which is distributed with perl, might be what
+you want. It handles that extra work.
 
 =head1 Data: Misc

-- 
brian d foy, [EMAIL PROTECTED]

Reply via email to