my @new_array = do {
my %bobs_your_uncle;
grep !$bobs_your_uncle{$_->{bob}}++, @array;
};
Basically, the do{} block executes the code inside the braces; you could call a sub and get the same effect here. The last statement in the block is the grep which returns a list, which is what ends up in @new_array.
The first line declares a hash. Nothing special about that. The magic's in the second line.
grep CONDITION, LIST returns a list of the members of LIST that match the CONDITION. Here, the magic's almost all in the construction of the condition.
$_->{bob} is the value associated with the "bob" key of the current element of the array (which is reference to a hash). e.g. if the current element of the array is (to put it visually),
{ bob=>'carol', alice=>"ted" }
$_->{bob} is "carol". OK, so we ask the question: is $bobs_your_uncle{carol} true? Well, if it's the first time we've seen it, no. That value's undefined. So that test -- with the negation in front of it -- turns out *TRUE* the first time "carol" is seen as the value of "bob" in the array. The value is undefined, which is false; not-that is true.
The ++ on the end of the condition says "OK, increment $bobs_your_uncle{carol} by 1 after you've performed the test", which means that, AFTER the element's been pushed or not pushed onto the result list, the value gets incremented.
Bottom line: if this is the first time the grep "loop" has seen "carol", the undef gets converted to 0, and the value of $bobs_your_uncle{carol} is set to 1.
Thus, the next time "carol" is seen, the condition evaluates to "false" (not-true: positive integer values are true in Perl), and the value is not pushed onto the result list.
All of which goes to show how frickin' cool this language is.
perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>);
+$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth
+er_name\n"'
|