如何从PHP多维数组中删除重复值

如何从PHP多维数组中删除重复值?

示例数组:

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
)


)
331477 次浏览

array_unique ()文档中的用户注释对此有许多解决方案。这是其中之一:

< p > Kenrbnsn at rbnsn.com < br > 27日- 9月- 2005年吸< / p >

另一个用于多维数组的Array_Unique。我只在二维数组上测试过这个,但它可能可以推广到更多的地方,或者使用递归。

这个函数使用serialize、array_unique和unserialize函数来完成工作。


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

它来自http://ca3.php.net/manual/en/function.array-unique.php#57202

另一种方式。也会保存密钥。

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

这里有另一种方法。不保存中间变量。

我们使用它来消除来自各种重叠查询的重复结果。

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

一个简单的解决方案,可能不是最有效的:

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;


}

我也遇到过类似的问题,但我找到了一个100%有效的解决方案。

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


?>

从5.2.9开始,如果你像这样使用SORT_REGULAR标志,你可以使用array_unique():

array_unique($array, SORT_REGULAR);

这使得函数比较元素是否相等,就像使用了$a == $b一样,这非常适合您的情况。

输出

Array
(
[0] => Array
(
[0] => abc
[1] => def
)


[1] => Array
(
[0] => ghi
[1] => jkl
)


[2] => Array
(
[0] => mno
[1] => pql
)


)

但是请记住,的文档声明:

array_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"
}
}

* /

如果您需要消除特定键上的重复项,例如mysqli id,这里有一个简单的函数

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

< >强加分 你可以传递一个键数组并添加一个外部foreach,但是每增加一个键速度会慢2倍

我对这个问题进行了大量的思考,并确定了最佳解决方案应该遵循两个规则。

  1. 为了可伸缩性,在适当的地方修改数组;不复制到新数组
  2. 对于性能,每个比较应该只进行一次

考虑到这一点,并考虑到PHP的所有特性,下面是我提出的解决方案。与其他一些答案不同,它能够根据您想要的任何键删除元素。输入数组应该是数字键。

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

唯一的缺点是迭代完成时键不是按顺序排列的。如果你随后只使用foreach循环,这不是问题,但如果你需要使用for循环,你可以在上面后面加上$input = array_values($input);来重新编号键。

正如人们所说的array_unique()非常慢,下面是我用于一个层次多维数组的代码片段。

$serialized_array = array_map("serialize", $input);


foreach ($serialized_array as $key => $val) {
$result[$val] = true;
}


$output = array_map("unserialize", (array_keys($result)));

引用第一个用户贡献的array_unique() php.net中的函数页面注释

如果你有一个这样的数组:

(users是数组的名称)

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

如果你想删除重复的文件,那么:

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

可以是一个解决方案:P

如果"remove duplicate "的意思是"remove duplicate,但保留一个",一个解决方案可能是首先在"identifier column"上应用array_unique(...),然后在原始数组中删除所有已从列数组中删除的键:

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

结果是:

Array
(
[0] => Array
(
[id] => 123
[foo] => aaa
[bar] => bbb
)


[2] => Array
(
[id] => 567
[foo] => eee
[bar] => fff
)


)

很多人问我如何制作唯一的多维数组。我参考了你的评论,这对我有帮助。

首先,感谢@jeromegamez @daveilers提供的解决方案。但每次我给出答案时,他们都会问我“序列化”和“反序列化”是如何工作的。这就是为什么我想和大家分享这个原因,这样可以帮助更多的人理解这背后的概念。

我解释了为什么我们使用“serialize”和“unserialize”的步骤:

步骤1:将多维数组转换为一维数组

要将多维数组转换为一维数组,首先生成数组内所有元素(包括嵌套数组)的字节流表示。Serialize()函数可以生成值的字节流表示。为了生成所有元素的字节流表示,调用array_map()函数中的serialize()函数作为回调函数。结果将是一个一维数组,无论多维数组有多少层。

步骤2:使值唯一

要使这个一维数组唯一,请使用array_unique()函数。

步骤3:将其还原为多维数组

虽然数组现在是唯一的,但值看起来像字节流表示。要将其还原为多维数组,请使用unserialize()函数。

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

再次感谢你所做的一切。

唯一一个多维数组的简单而合理的方法如下:

如果你有一个这样的数组:

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

使用foreach来解决这个问题:

foreach($array as $k=>$v){
$unique=array_unique($v);
$array[$k]=$unique;
}

它会给你以下结果:

Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[3] => Value3
[4] => Value4
)
)

如果你想重新排列键的顺序,

foreach($array as $k=>$v){
$unique= array_values(array_unique($v));
$array[$k]=$unique;
}

这个操作会给你这样排列的键值:

Array
(
[Key1] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
)
[Key2] => Array
(
[0] => Value1
[1] => Value2
[2] => Value3
[3] => Value4
)
)

我希望这能澄清一切。

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

这将从数组中删除重复的名称。按键唯一

根据标记为正确的答案,添加我的答案。添加的小代码只是为了重置索引-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
尝试此解决方案的(n)维度数组与未限制长度
例如这个数组

$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"
]
];

这就是答案

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

这个解决方案只在一个数组列需要唯一性时才有用,例如,如果我们需要数组索引#0中的唯一性。

解决方案1:

使用array_filter匿名函数静态变量:

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

解决方案2:

由于我们想要唯一性的值是字符串类型,我们可以重新映射原始全局数组,使用这些值作为键,这将在我们重新映射时删除重复的值:

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