How to remove duplicate values from a multi-dimensional array in PHP

    |
  • Added:
  • |
  • In: Basic PHP

How can I remove duplicate values from a multi-dimensional array in PHP?

Example array:

Array ( [0] => Array ( [0] => abc [1] => def ) [1] => Array ( [0] => ghi [1] => jkl ) [2] => Array ( [0] => mno [1] => pql ) [3] => Array ( [0] => abc [1] => def ) [4] => Array ( [0] => ghi [1] => jkl ) [5] => Array ( [0] => mno [1] => pql ) ) 
This Question Has 15 Answeres | Orginal Question | Ian

I've given this problem a lot of thought and have determined that the optimal solution should follow two rules.

  1. For scalability, modify the array in place; no copying to a new array
  2. For performance, each comparison should be made only once

With that in mind and given all of PHP's quirks, below is the solution I came up with. Unlike some of the other answers, it has the ability to remove elements based on whatever key(s) you want. The input array is expected to be numeric keys.

$count_array = count($input); for ($i = 0; $i < $count_array; $i++) { if (isset($input[$i])) { for ($j = $i+1; $j < $count_array; $j++) { if (isset($input[$j])) { //this is where you do your comparison for dupes if ($input[$i]['checksum'] == $input[$j]['checksum']) { unset($input[$j]); } } } } } 

The only drawback is that the keys are not in order when the iteration completes. This isn't a problem if you're subsequently using only foreach loops, but if you need to use a for loop, you can put $input = array_values($input); after the above to renumber the keys.

Another way. Will preserve keys as well.

function array_unique_multidimensional($input) { $serialized = array_map('serialize', $input); $unique = array_unique($serialized); return array_intersect_key($input, $unique); } 

If you have an array like this

data = array ( [0] => array ( [subject] => a [object] => c ), [1] => array ( [subject] => b [object] => d ), [2] => array ( [subject] => d [object] => b ), [3] => array ( [subject] => d [object] => c ), [4] => array ( [subject] => c [object] => a ), [5] => array ( [subject] => c [object] => d ) ) 

and you want to get arrays like this:

data = array ( [0] => array ( [subject] => a [object] => c ), [1] => array ( [subject] => b [object] => d ), [2] => array ( [subject] => d [object] => c ) ) 

or

data = array ( [0] => array ( [subject] => d [object] => b ), [1] => array ( [subject] => c [object] => a ), [2] => array ( [subject] => c [object] => d ) ) 

a following code can help

 $data1 = array(); $data1 = $data; for($q=0;$q<count($data);$q++) { for($p=0;$p<count($data1);$p++) { if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"])) { $data1[$p]["subject"] = $data[$q]["subject"]; $data1[$p]["object"] = $data[$q]["object"]; } } } $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1)))); $data = $data1; 

I had a similar problem but I found a 100% working solution for it.

<?php $arr=""; $arr[0]['id']=0; $arr[0]['titel']="ABC"; $arr[1]['id']=1; $arr[1]['titel']="DEF"; $arr[2]['id']=2; $arr[2]['titel']="ABC"; $arr[3]['id']=3; $arr[3]['titel']="XYZ"; echo "<pre>"; print_r($arr); echo "unique*********************<br/>"; print_r(super_unique($arr,'titel')); function super_unique($array,$key) { $temp_array = array(); foreach ($array as &$v) { if (!isset($temp_array[$v[$key]])) $temp_array[$v[$key]] =& $v; } $array = array_values($temp_array); return $array; } ?> 

Since 5.2.9 you can use array_unique() if you use the SORT_REGULAR flag like so:

array_unique($array, SORT_REGULAR); 

This makes the function compare elements for equality as if $a == $b were being used, which is perfect for your case.

Output

Array ( [0] => Array ( [0] => abc [1] => def ) [1] => Array ( [0] => ghi [1] => jkl ) [2] => Array ( [0] => mno [1] => pql ) ) 

Keep in mind, though, that the documentation states:

array_unique() is not intended to work on multi dimensional arrays.

Here is another way. No intermediate variables are saved.

We used this to de-duplicate results from a variety of overlapping queries.

$input = array_map("unserialize", array_unique(array_map("serialize", $input))); 

Just use SORT_REGULAR option as second parameter.

$uniqueArray = array_unique($array, SORT_REGULAR); 

Lots of person asked me how to make Unique multidimensional array. I have taken reference from your comment and it helps me.

First of All, Thanks to @jeromegamez @daveilers for your solution. But every time i gave the answer, they asked me how this 'serialize' and 'unserialize' works. That's why i want to share the reason of this with you so that it will help more people to understand the concept behind this.

I am explaining why we use 'serialize' and 'unserialize' in steps :

Step 1: Convert the multidimensional array to one-dimensional array

To convert the multidimensional array to a one-dimensional array, first generate byte stream representation of all the elements (including nested arrays) inside the array. serialize() function can generate byte stream representation of a value. To generate byte stream representation of all the elements, call serialize() function inside array_map() function as a callback function. The result will be a one dimensional array no matter how many levels the multidimensional array has.

Step 2: Make the values unique

To make this one dimensional array unique, use array_unique() function.

Step 3: Revert it to the multidimensional array

Though the array is now unique, the values looks like byte stream representation. To revert it back to the multidimensional array, use unserialize() function.

$input = array_map("unserialize", array_unique(array_map("serialize", $input))); 

Thanks again for all this.

If "remove duplicates" means "remove duplicates, but let one there", a solution might be to apply the array_unique(...) on the "identifier column" first and then to remove in the original array all the keys, that have been removed from the column array:

$array = [ [ 'id' => '123', 'foo' => 'aaa', 'bar' => 'bbb' ], [ 'id' => '123', 'foo' => 'ccc', 'bar' => 'ddd' ], [ 'id' => '567', 'foo' => 'eee', 'bar' => 'fff' ] ]; $ids = array_column($array, 'id'); $ids = array_unique($ids); $array = array_filter($array, function ($key, $value) use ($ids) { return in_array($value, array_keys($ids)); }, ARRAY_FILTER_USE_BOTH); 

The result is:

Array ( [0] => Array ( [id] => 123 [foo] => aaa [bar] => bbb ) [2] => Array ( [id] => 567 [foo] => eee [bar] => fff ) ) 

As people are saying array_unique() is very slow, here is a snippet I use for one level multidimensional array.

$serialized_array = array_map("serialize", $input); foreach ($serialized_array as $key => $val) { $result[$val] = true; } $output = array_map("unserialize", (array_keys($result))); 

Reference first user contributed note of array_unique() function page in php.net

The user comments on the array_unique() documentation have many solutions to this. Here is one of them:

kenrbnsn at rbnsn dot com
27-Sep-2005 12:09

Yet another Array_Unique for multi-demensioned arrays. I've only tested this on two-demensioned arrays, but it could probably be generalized for more, or made to use recursion.

This function uses the serialize, array_unique, and unserialize functions to do the work.

 function multi_unique($array) { foreach ($array as $k=>$na) $new[$k] = serialize($na); $uniq = array_unique($new); foreach($uniq as $k=>$ser) $new1[$k] = unserialize($ser); return ($new1); }

This is from http://ca3.php.net/manual/en/function.array-unique.php#57202.

An alternative to serialize and unique

$test = [ ['abc','def'], ['ghi','jkl'], ['mno','pql'], ['abc','def'], ['ghi','jkl'], ['mno','pql'], ]; $result = array_reduce( $test, function($carry,$item){ if(!in_array($item,$carry)) { array_push($carry,$item); } return $carry; }, [] ); var_dump($result); /* php unique.php array(3) { [0] => array(2) { [0] => string(3) "abc" [1] => string(3) "def" } [1] => array(2) { [0] => string(3) "ghi" [1] => string(3) "jkl" } [2] => array(2) { [0] => string(3) "mno" [1] => string(3) "pql" } } 

*/

An easy to read solution, probably not the most efficient:

function arrayUnique($myArray){ if(!is_array($myArray)) return $myArray; foreach ($myArray as &$myvalue){ $myvalue=serialize($myvalue); } $myArray=array_unique($myArray); foreach ($myArray as &$myvalue){ $myvalue=unserialize($myvalue); } return $myArray; } 

if you need to eliminate duplicates on specific keys, such as a mysqli id, here's a simple funciton

function search_array_compact($data,$key){ $compact = []; foreach($data as $row){ if(!in_array($row[$key],$compact)){ $compact[] = $row; } } return $compact; } 

Bonus Points You can pass an array of keys and add an outer foreach, but it will be 2x slower per additional key.

if you have an array like this:

(users is the name of the array)

Array=> [0] => (array) 'user' => 'john' 'age' => '23' [1] => (array) 'user' => 'jane' 'age' => '20' [2]=> (array) 'user' => 'john' 'age' => '23' 

and you want to delete duplicates...then:

$serialized = array(); for ($i=0; $i < sizeof($users); $i++) { $test = in_array($users['user'], $serialized); if ($test == false) { $serialized[] = $users['user']; } } 

can be a solution :P


Search
I am...

Sajjad Hossain

I have five years of experience in web development sector. I love to do amazing projects and share my knowledge with all.

Connect Social With PHPAns
Top