Using array_unique() with multidimensional arrays

Permanent Link: Using array_unique() with multidimensional arrays 31. Januar 2009 RSS Feed for comments on RSS-Feed für Kommentare zu: Using array_unique() with multidimensional arrays comments feed

There's one problem with array_unique(): It doesn't work with multidimensional arrays. Here's an example:

$array = array(
array(
'id' => 123,
'name' => 'Some Product',
'ean' => '1234567890123'
),
array(
'id' => 123,
'name' => 'Some Product',
'ean' => '4852950174938'
),
array(
'id' => 123,
'name' => 'Some Product',
'ean' => '1234567890123'
),
);
$uniqueArray = array_unique($array);
var_dump($uniqueArray);

Two elements are exactly the same, but one element has a different EAN, yet the var_dump() returns the following:

array(1) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(12) "Some Product"
["ean"]=>
string(13) "1234567890123"
}
}

Obviously this is unexpected behaviour. array_unique() threw out the second element, which is clearly not the same as Element 1 and 3. The easiest way I came across is using md5 hashes for comparison of the elements. All you need is to iterate over the first dimension, serialize it and create a MD5 hash of it for comparison:

/**
* Create Unique Arrays using an md5 hash
*
* @param array $array
* @return array
*/
function arrayUnique($array, $preserveKeys = false)
{
// Unique Array for return
$arrayRewrite = array();
// Array with the md5 hashes
$arrayHashes = array();
foreach($array as $key => $item) {
// Serialize the current element and create a md5 hash
$hash = md5(serialize($item));
// If the md5 didn't come up yet, add the element to
// to arrayRewrite, otherwise drop it
if (!isset($arrayHashes[$hash])) {
// Save the current element hash
$arrayHashes[$hash] = $hash;
// Add element to the unique Array
if ($preserveKeys) {
$arrayRewrite[$key] = $item;
} else {
$arrayRewrite[] = $item;
}
}
}
return $arrayRewrite;
}

$uniqueArray = arrayUnique($array);
var_dump($uniqueArray);

Now the result is the one array_unique() should have already given:

array(2) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(12) "Some Product"
["ean"]=>
string(13) "1234567890123"
}
[1]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(12) "Some Product"
["ean"]=>
string(13) "4852950174938"
}
}

This works with as many dimensions as you like.

11 comments

Peter Rothers Gravatar

Peter Rother
09.02.2009, 18:45 o'clock

Nice example, thx. I think i can use it in future projects.

Lorems Gravatar

Lorem
24.02.2009, 16:42 o'clock

Did you fill in a bug report? This is really bad behavior.

Jeremys Gravatar

Jeremy
10.03.2009, 22:45 o'clock

Thank you. Clear, concise, fast. Works fantastic. Well done and thanks again.

Dominik Jungowskis Gravatar

Dominik Jungowski
13.03.2009, 11:57 o'clock

@Lorem: I just did (although there was already a similar bug report from 2001): http://bugs.php.net/bug.php?id=47642

Franks Gravatar

Frank
05.05.2009, 00:29 o'clock

I need a fix for this as I've stumbled across this bug today. Unfortunately, your code outputs the exact same result as array_unique().

Dominik Jungowskis Gravatar

Dominik Jungowski
05.05.2009, 09:34 o'clock

An example where it puts out the same would be nice.

As for the example from the blogpost: I have just tested it once more and it worked as it should.

btw. the bug report was closed ("was never intended to work with multi-dimensional arrays") but at least the documentation has been updated

Dominik Jungowskis Gravatar

Dominik Jungowski
12.06.2009, 16:46 o'clock

There was indeed one bug when using associative arrays. For that reason I updated the blogpost and added the preserveKeys parameter to the function.

zeromatrix
15.11.2009, 02:05 o'clock

Thank you very much for this knowledge. After Change the PHP version 4 to 5 my old code are not workin correct, but this works very fine !!


17.12.2009, 08:43 o'clock

awesome - this rocks! and so do you!!

Mukuls Gravatar

Mukul
12.02.2010, 14:12 o'clock

Thanks for this piece of code…

John Flynns Gravatar

John Flynn
01.03.2010, 21:03 o'clock

I have borrowed this functionality and left credit in the comments. Good idea. Thanks!

Write a comment

(will not be published)