I don’t understand the last line of this function from Programming Perl 3e.
Here’s how you might write a function that does a kind of set intersection by returning a list of keys occurring in all the hashes passed to it:
@common = inter( \%foo, \%bar, \%joe ); sub inter { my %seen; for my $href (@_) { while (my $k = each %$href) { $seen{$k}++; } } return grep { $seen{$_} == @_ } keys %seen; }
I understand that %seen is a hash which maps each key to the number of times it was encountered in any of the hashes provided to the function.
grepwill take a list passed to it (in this case, every element seen in any of the hashrefs); and return a list of only those elements where the expression in the block is true (locally setting$_variable to each element in the list).Let’s look at how that expression is evaluated:
@_is an array of all the parameters passed to the subroutine – in our case a list of hash references passed in.In
$seen{$_} == @_expression that list is forced into a scalar context (due to==).When used in a scalar context, a list evaluates to the number of elements in a list – in the example call above, to 3, since 3 hashrefs were passed in.
So, for each key in
%seen(e.g. each key seen in any of N hashrefs); the expression$seen{$_} == @_is numerically comparing the # of times the element was seen in the hashes to the total number of hashes – it’s only going to be equal, of course, if the element is in ALL the hashes that were passed in, and thus a member of the intersection we want.So, to sum up the analysis, the grep will return a list of all keys that occur in EVERY hash (aka occur N times where N is the # of hashes). E.g. an intersection.