Olsi
Olsi

Reputation: 89

Translate one line of Perl to PHP

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.

Upvotes: 4

Views: 158

Answers (2)

DavidO
DavidO

Reputation: 13942

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.

Upvotes: 7

mpapec
mpapec

Reputation: 50637

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));

Upvotes: 2

Related Questions