I am translating a file from Perl to PHP, but I need help with this line:@stuff_unique = grep !$list{$_}++, @stuff;
.
I know stuff_unique
and stuff
are arrays.
This is a common Perl idiom, described in perlfaq4
With this construct, @stuff_unique
will end up with a list of items that were seen at least once in @stuff
; in other words, it is left holding only unique values, in the sense that there will be no repeats. The way it works is this:
A hash, in Perl, is like an associative array with unique keys. %list
is such a hash. $list{something}
is an element in that hash named 'something'. Its value can be whatever you place in it.
grep
iterates over the items in @stuff
. For each item in stuff
, that item is used as a hash key in the %list
hash. The ++
increments the value for that corresponding hash element. So if @stuff
contained "1, 2, 1", then on the first iteration a hash element named "1" would be created. It has no value, which translates to Boolean false. The !
in front reverses the Boolean sense. So on that first iteration, the false value for the '1' hash element is evaluated as true, so that element passes through to @stuff_unique
. Finally, post-increment takes place, so the value held in the 1
hash element increments to 1.
On the second element, the 2 has also not yet been seen, so it passes through, and its corresponding hash element is also incremented to 1.
On the third iteration, a '1' is seen again. $list{1}
is already equal to 1
, which is a true value. !true is false; so this one doesn't pass through to @stuff_unique
.
One by one the elements in @stuff
will be tested in this way; detecting if they've been seen before, and if they haven't, they pass through to @stuff_unique
.
PHP provides a function called array_unique, which should do the same thing for you. It would be used like this:
$stuff_unique = array_unique($stuff);
Fortunately for the Perl people, this is a linear-time operation. Unfortunately for the PHP people, this is implemented internally by sorting the input array, and then iterating over it, skipping duplicates along the way. That means it's a O(n + n log n)
operation (simplified to O(n log n)
), which is to say, its implementation can't scale as well as the common Perl idiom.
The joy of using php closures,
<?php
$stuff = array(1,1,2,2,2,3,3,3);
$list = array();
$stuff_unique = array_filter($stuff, function($_) use (&$list) {
return !$list[$_]++;
});
print_r(array_values($stuff_unique));
or
<?php
$stuff = array(1,1,2,2,2,3,3,3);
$stuff_unique = array_keys(array_flip($stuff));
print_r($stuff_unique);
or
$stuff_unique = array_values(array_unique($stuff));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With