How to remove duplicate values from a multi-dimensional array in PHP - 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
)
)

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

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.

I had a similar problem but I found a 100% working solution for it.
<?php
function super_unique($array,$key)
{
$temp_array = [];
foreach ($array as &$v) {
if (!isset($temp_array[$v[$key]]))
$temp_array[$v[$key]] =& $v;
}
$array = array_values($temp_array);
return $array;
}
$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'));
?>

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

Array
(
[0] => Array
(
[id] => 1
[name] => john
)
[1] => Array
(
[id] => 2
[name] => smith
)
[2] => Array
(
[id] => 3
[name] => john
)
[3] => Array
(
[id] => 4
[name] => robert
)
)
$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);
This will remove the duplicate names from array. unique by key

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

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.

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

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.

A very easy and logical way to Unique a multi dimension array is as follows,
If you have array like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value1
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value4
)
)
use foreach to solve this:
foreach($array as $k=>$v){
$unique=array_unique($v);
$array[$k]=$unique;
}
it will give you following result:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
[4] => Value4
)
)
and if you want to rearrange the order of the keys,
foreach($array as $k=>$v){
$unique= array_values(array_unique($v));
$array[$k]=$unique;
}
This operation will give you arranged key values like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
[3] => Value4
)
)
I hope this will clear everything.

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

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

This solution is relevant only when uniqueness is needed for one array column, for example here if we need the uniqueness in index #0 of the arrays.
Solution #1:
Using array_filter with an anonymous function and a static variable:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$list = array_filter($list, function ($item) {
static $values = [];
if (!in_array($item[0], $values)) {
$values[] = $item[0];
return true;
} else {
return false;
}
});
var_dump($list);
Solution #2:
Since the value when we want the uniqueness are of string type, we can remap the original global array to use these values as keys, which will remove duplicates as we remap it:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$unique = [];
foreach ($list as $item) {
$unique[$item[0]] = $item;
}
// Remap again to integers
$unique = array_values($unique);
var_dump($unique);

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"
}
}
*/

I've given this problem a lot of thought and have determined that the optimal solution should follow two rules.
For scalability, modify the array in place; no copying to a new array
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.

try this solution for (n) Dimensional array with non-restricted length
for example this array
$arr= [
0 => [0=>"a" , 1=>"b" , 2=>"c" ] ,
1 => [0=>"x" , 1=>"b" , 2=>"a", 3=>"p"],
2=> [
[
0=>"y" ,
1=>"b" ,
2=> [0=>"x" , 1=>"m" , 2=>"a"]
],
1=>"z" ,
2=>"v"
]
];
This would be the solution
$ar2=[];
$ar3=[];
function test($arr){
global $ar2,$ar3;
if(is_array($arr)){
return array_map("test",$arr);
}
if(!isset($ar2[$arr])){
$ar2[$arr]=1;
$ar3[]=$arr;
}
}
array_map("test",$arr);
print_r($ar3);

Based on the Answer marked as correct, adding my answer. Small code added just to reset the indices-
$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));

Related

Remove subsets from each row where the same subset is found in another row

I need to remove objects from a 3d array where the same two-property object is found in any other row.
I previously asked this similar question, but my new requirements are slightly different because I was keeping one of the encountered duplicates. Now I would like for both/all encountered duplicates to be removed.
[
[
["name" => "John", "surname" => "Smith"],
["name" => "Kate", "surname" => "Winston"]
],
[
["name" => "Kate", "surname" => "Winston"],
["name" => "Jack", "surname" => "Irving"]
],
]
Desired filtered result with same original structure:
[
[
["name" => "John", "surname" => "Smith"],
],
[
["name" => "Jack", "surname" => "Irving"]
],
]
Seems like others answers don't see their own final results and don't read desired output.
Here a little bit hard solution but it works well.
Note: the input data array must have 2 object indexes and 2 arrays of objects for comparing, otherwise, it should be fixed.
$ar = Array (
0 => [(object)["name"=>"John", "surname"=>"Smith"], (object)["name"=>"Kate", "surname"=>"Winston"]],
1 => [(object)["name"=>"Kate", "surname"=>"Winston"], (object)["name"=>"Jack", "surname"=>"Irving"]]
);
$arr = [];
$k = 0; // do `if statement` only once
foreach($ar as $num=>&$subar){
foreach($subar as $num2=>$pers){
$subar[$num2] = (array)$pers; // object to array
if (!$k) {
$keys = array_keys($subar[$num2]); // collect "name" and "surname" in an array
$k++;
}
foreach($subar[$num2] as $a=>$b){
$seq = array_search($a,$keys); // index of the current key
if (!$seq) { // 0 -> "name", 1 -> "surname"
$arr[$num][$b] = '';
} else {
$arr[$num][$subar[$num2][current($keys)]] = $b;
}
}
}
}
$diff[] = array_diff($arr[0],$arr[1]); // clear duplicates from 1-st set
$diff[] = array_diff($arr[1],$arr[0]); // clear duplicates from 2-nd set
Gives result:
Array
(
[0] => Array
(
[John] => Smith
)
[1] => Array
(
[Jack] => Irving
)
)
And after you can re-create the output array:
// creating a new array
$res = [];
foreach($diff as $num=>$ns){
foreach($ns as $name=>$surname){
foreach($keys as $ind=>$key){
if ($ind % 2 == 0){
$tmp[$key] = $name; // put name
} else {
$tmp[$key] = $surname; // put surname
}
}
$res[$num] = (object)$tmp; // array to object
}
}
Output will be:
Array
(
[0] => stdClass Object
(
[name] => John
[surname] => Smith
)
[1] => stdClass Object
(
[name] => Jack
[surname] => Irving
)
)
Demo
In case of string values in the input arrays, i.e.:
$ar = [
'[{"name":"John", "surname":"Smith"}, {"name":"Kate", "surname":"Winston"}]',
'[{"name":"Kate", "surname":"Winston"}, {"name":"Jack", "surname":"Irving"}]'
];
You need a little fix:
...
foreach($ar as $num=>&$subar){
$ar[$num] = json_decode($subar);
foreach($subar as $num2=>$pers){
...
The same output you will get.
Demo
It's easier if you don't trim away the brackets [], as you stated that you did in the comments. That way, they are proper JSON strings, which we can use in PHP.
Map (or loop) over your array, and build up a $result array, where you append all the arrays from your decoded JSON. Once you have your final $result, you have an array that looks somewhat like
Array (
[0] => Array
(
[name] => John
[surname] => Smith
)
[1] => Array
(
[name] => Kate
[surname] => Winston
)
[2] => Array
(
[name] => Kate
[surname] => Winston
)
[3] => Array
(
[name] => Jack
[surname] => Irving
)
)
We have all the values in an actual array now, but there are duplicates -- which can be removed using array_unique() with the SORT_REGULAR flag.
$array = [
'[{"name":"John", "surname":"Smith"}, {"name":"Kate", "surname":"Winston"}]',
'[{"name":"Kate", "surname":"Winston"}, {"name":"Jack", "surname":"Irving"}]'
];
$result = [];
array_map(function($v) use (&$result) {
$result = array_merge($result, json_decode($v, true));
}, $array);
print_r(array_unique($result, SORT_REGULAR));
Final output:
Array
(
[0] => Array
(
[name] => John
[surname] => Smith
)
[1] => Array
(
[name] => Kate
[surname] => Winston
)
[3] => Array
(
[name] => Jack
[surname] => Irving
)
)
Live demo at https://3v4l.org/q6pZc
$array = [
'[{"name":"John", "surname":"Smith"}, {"name":"Kate", "surname":"Winston"}]',
'[{"name":"Kate", "surname":"Winston"}, {"name":"Jack", "surname":"Irving"}]'
];
$resultArray = [];
foreach ($array as $item) {
$bufferArray = array_merge($resultArray, json_decode($item));
foreach ($bufferArray as $elements) {
$key = $elements->name . $elements->surname;
if (array_key_exists($key, $resultArray)) {
unset($resultArray[$key]);
} else {
$resultArray[$key] = $elements;
}
}
}
print_r($resultArray);
Output
Array
(
[KateWinston] => stdClass Object
(
[name] => Kate
[surname] => Winston
)
[JackIrving] => stdClass Object
(
[name] => Jack
[surname] => Irving
)
)
can rewrite this into more serious code )
To remove objects from each row where a given object exists any where in any other row, you can make iterates calls of array_udiff(). Inside the function, the first parameter should be the currently iterated row and the next/subsequent parameter(s) should all of the other rows in the entire array. The last parameter is the callback which compares whole objects to whole objects via PHP's performance-optimized algorithm.
My snippet below will not only handle your 2-row array, it will also handle arrays with 3 or more rows.
Code: (Demo)
$result = [];
foreach ($array as $i => $objs) {
$cache = $array[$i];
unset($array[$i]);
$params = [
$objs,
...$array,
fn($a, $b) => $a <=> $b
];
$result[] = array_udiff(...$params);
$array[$i] = $cache;
}
var_export($result);
To be clear, this snippet will work the same if the array of arrays of objects is an array of arrays of arrays.

Remove duplicates from a php array by a specific multi-dimensional array key that is nested [duplicate]

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
)
)
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)));
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.
I had a similar problem but I found a 100% working solution for it.
<?php
function super_unique($array,$key)
{
$temp_array = [];
foreach ($array as &$v) {
if (!isset($temp_array[$v[$key]]))
$temp_array[$v[$key]] =& $v;
}
$array = array_values($temp_array);
return $array;
}
$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'));
?>
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);
}
Array
(
[0] => Array
(
[id] => 1
[name] => john
)
[1] => Array
(
[id] => 2
[name] => smith
)
[2] => Array
(
[id] => 3
[name] => john
)
[3] => Array
(
[id] => 4
[name] => robert
)
)
$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);
This will remove the duplicate names from array. unique by key
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
)
)
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.
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
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.
A very easy and logical way to Unique a multi dimension array is as follows,
If you have array like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value1
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value4
)
)
use foreach to solve this:
foreach($array as $k=>$v){
$unique=array_unique($v);
$array[$k]=$unique;
}
it will give you following result:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
[4] => Value4
)
)
and if you want to rearrange the order of the keys,
foreach($array as $k=>$v){
$unique= array_values(array_unique($v));
$array[$k]=$unique;
}
This operation will give you arranged key values like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
[3] => Value4
)
)
I hope this will clear everything.
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;
}
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
This solution is relevant only when uniqueness is needed for one array column, for example here if we need the uniqueness in index #0 of the arrays.
Solution #1:
Using array_filter with an anonymous function and a static variable:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$list = array_filter($list, function ($item) {
static $values = [];
if (!in_array($item[0], $values)) {
$values[] = $item[0];
return true;
} else {
return false;
}
});
var_dump($list);
Solution #2:
Since the value when we want the uniqueness are of string type, we can remap the original global array to use these values as keys, which will remove duplicates as we remap it:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$unique = [];
foreach ($list as $item) {
$unique[$item[0]] = $item;
}
// Remap again to integers
$unique = array_values($unique);
var_dump($unique);
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"
}
}
*/
I've given this problem a lot of thought and have determined that the optimal solution should follow two rules.
For scalability, modify the array in place; no copying to a new array
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.
try this solution for (n) Dimensional array with non-restricted length
for example this array
$arr= [
0 => [0=>"a" , 1=>"b" , 2=>"c" ] ,
1 => [0=>"x" , 1=>"b" , 2=>"a", 3=>"p"],
2=> [
[
0=>"y" ,
1=>"b" ,
2=> [0=>"x" , 1=>"m" , 2=>"a"]
],
1=>"z" ,
2=>"v"
]
];
This would be the solution
$ar2=[];
$ar3=[];
function test($arr){
global $ar2,$ar3;
if(is_array($arr)){
return array_map("test",$arr);
}
if(!isset($ar2[$arr])){
$ar2[$arr]=1;
$ar3[]=$arr;
}
}
array_map("test",$arr);
print_r($ar3);
Based on the Answer marked as correct, adding my answer. Small code added just to reset the indices-
$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));

Remove duplicates based on inner value from multidimensional arrays [duplicate]

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
)
)
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)));
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.
I had a similar problem but I found a 100% working solution for it.
<?php
function super_unique($array,$key)
{
$temp_array = [];
foreach ($array as &$v) {
if (!isset($temp_array[$v[$key]]))
$temp_array[$v[$key]] =& $v;
}
$array = array_values($temp_array);
return $array;
}
$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'));
?>
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);
}
Array
(
[0] => Array
(
[id] => 1
[name] => john
)
[1] => Array
(
[id] => 2
[name] => smith
)
[2] => Array
(
[id] => 3
[name] => john
)
[3] => Array
(
[id] => 4
[name] => robert
)
)
$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);
This will remove the duplicate names from array. unique by key
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
)
)
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.
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
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.
A very easy and logical way to Unique a multi dimension array is as follows,
If you have array like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value1
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value4
)
)
use foreach to solve this:
foreach($array as $k=>$v){
$unique=array_unique($v);
$array[$k]=$unique;
}
it will give you following result:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
[4] => Value4
)
)
and if you want to rearrange the order of the keys,
foreach($array as $k=>$v){
$unique= array_values(array_unique($v));
$array[$k]=$unique;
}
This operation will give you arranged key values like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
[3] => Value4
)
)
I hope this will clear everything.
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;
}
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
This solution is relevant only when uniqueness is needed for one array column, for example here if we need the uniqueness in index #0 of the arrays.
Solution #1:
Using array_filter with an anonymous function and a static variable:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$list = array_filter($list, function ($item) {
static $values = [];
if (!in_array($item[0], $values)) {
$values[] = $item[0];
return true;
} else {
return false;
}
});
var_dump($list);
Solution #2:
Since the value when we want the uniqueness are of string type, we can remap the original global array to use these values as keys, which will remove duplicates as we remap it:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$unique = [];
foreach ($list as $item) {
$unique[$item[0]] = $item;
}
// Remap again to integers
$unique = array_values($unique);
var_dump($unique);
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"
}
}
*/
I've given this problem a lot of thought and have determined that the optimal solution should follow two rules.
For scalability, modify the array in place; no copying to a new array
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.
try this solution for (n) Dimensional array with non-restricted length
for example this array
$arr= [
0 => [0=>"a" , 1=>"b" , 2=>"c" ] ,
1 => [0=>"x" , 1=>"b" , 2=>"a", 3=>"p"],
2=> [
[
0=>"y" ,
1=>"b" ,
2=> [0=>"x" , 1=>"m" , 2=>"a"]
],
1=>"z" ,
2=>"v"
]
];
This would be the solution
$ar2=[];
$ar3=[];
function test($arr){
global $ar2,$ar3;
if(is_array($arr)){
return array_map("test",$arr);
}
if(!isset($ar2[$arr])){
$ar2[$arr]=1;
$ar3[]=$arr;
}
}
array_map("test",$arr);
print_r($ar3);
Based on the Answer marked as correct, adding my answer. Small code added just to reset the indices-
$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));

How do I merge array values fo a multidimensional array [duplicate]

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
)
)
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)));
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.
I had a similar problem but I found a 100% working solution for it.
<?php
function super_unique($array,$key)
{
$temp_array = [];
foreach ($array as &$v) {
if (!isset($temp_array[$v[$key]]))
$temp_array[$v[$key]] =& $v;
}
$array = array_values($temp_array);
return $array;
}
$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'));
?>
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);
}
Array
(
[0] => Array
(
[id] => 1
[name] => john
)
[1] => Array
(
[id] => 2
[name] => smith
)
[2] => Array
(
[id] => 3
[name] => john
)
[3] => Array
(
[id] => 4
[name] => robert
)
)
$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);
This will remove the duplicate names from array. unique by key
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
)
)
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.
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
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.
A very easy and logical way to Unique a multi dimension array is as follows,
If you have array like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value1
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value4
)
)
use foreach to solve this:
foreach($array as $k=>$v){
$unique=array_unique($v);
$array[$k]=$unique;
}
it will give you following result:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
[4] => Value4
)
)
and if you want to rearrange the order of the keys,
foreach($array as $k=>$v){
$unique= array_values(array_unique($v));
$array[$k]=$unique;
}
This operation will give you arranged key values like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
[3] => Value4
)
)
I hope this will clear everything.
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;
}
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
This solution is relevant only when uniqueness is needed for one array column, for example here if we need the uniqueness in index #0 of the arrays.
Solution #1:
Using array_filter with an anonymous function and a static variable:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$list = array_filter($list, function ($item) {
static $values = [];
if (!in_array($item[0], $values)) {
$values[] = $item[0];
return true;
} else {
return false;
}
});
var_dump($list);
Solution #2:
Since the value when we want the uniqueness are of string type, we can remap the original global array to use these values as keys, which will remove duplicates as we remap it:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$unique = [];
foreach ($list as $item) {
$unique[$item[0]] = $item;
}
// Remap again to integers
$unique = array_values($unique);
var_dump($unique);
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"
}
}
*/
I've given this problem a lot of thought and have determined that the optimal solution should follow two rules.
For scalability, modify the array in place; no copying to a new array
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.
try this solution for (n) Dimensional array with non-restricted length
for example this array
$arr= [
0 => [0=>"a" , 1=>"b" , 2=>"c" ] ,
1 => [0=>"x" , 1=>"b" , 2=>"a", 3=>"p"],
2=> [
[
0=>"y" ,
1=>"b" ,
2=> [0=>"x" , 1=>"m" , 2=>"a"]
],
1=>"z" ,
2=>"v"
]
];
This would be the solution
$ar2=[];
$ar3=[];
function test($arr){
global $ar2,$ar3;
if(is_array($arr)){
return array_map("test",$arr);
}
if(!isset($ar2[$arr])){
$ar2[$arr]=1;
$ar3[]=$arr;
}
}
array_map("test",$arr);
print_r($ar3);
Based on the Answer marked as correct, adding my answer. Small code added just to reset the indices-
$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));

I want to make my array unique in php [duplicate]

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
)
)
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)));
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.
I had a similar problem but I found a 100% working solution for it.
<?php
function super_unique($array,$key)
{
$temp_array = [];
foreach ($array as &$v) {
if (!isset($temp_array[$v[$key]]))
$temp_array[$v[$key]] =& $v;
}
$array = array_values($temp_array);
return $array;
}
$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'));
?>
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);
}
Array
(
[0] => Array
(
[id] => 1
[name] => john
)
[1] => Array
(
[id] => 2
[name] => smith
)
[2] => Array
(
[id] => 3
[name] => john
)
[3] => Array
(
[id] => 4
[name] => robert
)
)
$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);
This will remove the duplicate names from array. unique by key
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
)
)
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.
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
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.
A very easy and logical way to Unique a multi dimension array is as follows,
If you have array like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value1
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value1
[3] => Value3
[4] => Value4
)
)
use foreach to solve this:
foreach($array as $k=>$v){
$unique=array_unique($v);
$array[$k]=$unique;
}
it will give you following result:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
[4] => Value4
)
)
and if you want to rearrange the order of the keys,
foreach($array as $k=>$v){
$unique= array_values(array_unique($v));
$array[$k]=$unique;
}
This operation will give you arranged key values like this:
Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
[3] => Value4
)
)
I hope this will clear everything.
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;
}
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
This solution is relevant only when uniqueness is needed for one array column, for example here if we need the uniqueness in index #0 of the arrays.
Solution #1:
Using array_filter with an anonymous function and a static variable:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$list = array_filter($list, function ($item) {
static $values = [];
if (!in_array($item[0], $values)) {
$values[] = $item[0];
return true;
} else {
return false;
}
});
var_dump($list);
Solution #2:
Since the value when we want the uniqueness are of string type, we can remap the original global array to use these values as keys, which will remove duplicates as we remap it:
<?php
$list = [
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql'],
['abc', 'def'],
['ghi', 'jkl'],
['mno', 'pql']
];
$unique = [];
foreach ($list as $item) {
$unique[$item[0]] = $item;
}
// Remap again to integers
$unique = array_values($unique);
var_dump($unique);
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"
}
}
*/
I've given this problem a lot of thought and have determined that the optimal solution should follow two rules.
For scalability, modify the array in place; no copying to a new array
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.
try this solution for (n) Dimensional array with non-restricted length
for example this array
$arr= [
0 => [0=>"a" , 1=>"b" , 2=>"c" ] ,
1 => [0=>"x" , 1=>"b" , 2=>"a", 3=>"p"],
2=> [
[
0=>"y" ,
1=>"b" ,
2=> [0=>"x" , 1=>"m" , 2=>"a"]
],
1=>"z" ,
2=>"v"
]
];
This would be the solution
$ar2=[];
$ar3=[];
function test($arr){
global $ar2,$ar3;
if(is_array($arr)){
return array_map("test",$arr);
}
if(!isset($ar2[$arr])){
$ar2[$arr]=1;
$ar3[]=$arr;
}
}
array_map("test",$arr);
print_r($ar3);
Based on the Answer marked as correct, adding my answer. Small code added just to reset the indices-
$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));

Categories