> -----Original Message----- > From: Merritt Krakowitzer [mailto:[EMAIL PROTECTED]] > Sent: Wednesday, July 24, 2002 4:19 AM > To: Bob Showalter; 'Timothy Johnson'; 'Beginners ' > Subject: RE: Comparing Arrays > > > I just found out I can shorten my one-liner to: > > > > @foo==@bar && "@{{map {$_, $_} @foo}}{@bar}" eq "@bar" > > Thanks, this was perfect for my situation, the arrays contain > file listing > in directories, > so there cant be duplicates. Well unless u have a file like > "foo" and "foo " > but thats highly unlikely i think. > > I was hoping you could explain your one liner to me from what > i can tell, it > *should* > be giving an error about being unable to coerce an array to a > hash, but it > seems to > work fine, it's driving me nuts :)
OK, here's how it works. @foo==@bar && "@{{map {$_, $_} @foo}}{@bar}" eq "@bar" ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Part A Part B Part A checks that the length of the two arrays is the same. The use of "==" causes the two operands to be evaulated in scalar context. Since an array name in scalar context evaluates to the number of elements in the array, we are comparing the lengths of the arrays. Part B checks that @foo contains each of the elements in @bar. Let's break it down: map {$_, $_} @foo map() constructs a list by evaluating the block repeatedly for each element in the input array, @foo. The block is evaulated in list context, so can return multiple values. Inside the block, $_ is aliased to the current value from @foo being processed. So the block {$_, $_} returns a pair of values for each input value. If @foo contains qw(foo bar baz), then the output of map will be qw(foo foo bar bar baz baz). { map {$_, $_} @foo } The braces here are an anonymous hash constructor. This turns the list into a reference to a hash. So, if @foo was qw(foo bar baz), we now have a hash that looks like foo=>'foo', bar=>'bar', baz=>'baz' @{{map {$_, $_} @foo}}{@bar} This is a hash slice operation. The basic format is: @{hashref}{list} The hashref is the anonymous hash created above. The list is the list of values from @bar. The hash slice returns a list of *values* from the hash which correspond to the *keys* named in the second list (i.e. @bar). Since the hash values and hash keys are the same (from the map() operation), and are just the entries from @foo, the result of the hash slice is a list of @foo entries matching each @bar entry, and in the order they appear in @bar. Now, if @bar contains an entry NOT found in the hash, the slice operation will return undef in that position in the list. For example, if @foo is qw(foo bar baz) and @bar is qw(baz qux foo), the hash slice will return the list 'baz', undef, 'foo'. Now the trick is to just compare these two lists. "@{{map {$_, $_} @foo}}{@bar}" eq "@bar" By enclosing the arrays in double quotes, I'm taking advantage of Perl's variable interpolation. When an array appears in double quotes, its elements are concatenated, with elements separated by the value of $" (by default, a space). So, in the example above, this expands to: "baz foo" eq "baz qux foo" (The undef in the second position expands to a zero-length string) Since these strings aren't equal, the two arrays aren't equal. Part A (checking the length of the arrays) is done to make sure @foo doesn't have "extra" elements not in @bar. The hash slicing business would not detect that. There may be other defects in this besides the duplicate issue I mentioned. -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]