如何从 PHP 中的多维数组中删除重复值
Posted
技术标签:
【中文标题】如何从 PHP 中的多维数组中删除重复值【英文标题】:How to remove duplicate values from a multi-dimensional array in PHP 【发布时间】:2010-09-23 09:19:05 【问题描述】:如何在 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
)
)
【问题讨论】:
【参考方案1】:array_unique() 文档中的用户 cmets 对此有很多解决方案。这是其中之一:
在 rbnsn dot com 上的 kenrbnsn 2005 年 9 月 27 日 12:09
另一个 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。
【讨论】:
【参考方案2】:另一种方式。也会保留密钥。
function array_unique_multidimensional($input)
$serialized = array_map('serialize', $input);
$unique = array_unique($serialized);
return array_intersect_key($input, $unique);
【讨论】:
对于大型数组,这种方法通常比公认的答案快至少 50%。【参考方案3】:这是另一种方式。不保存中间变量。
我们使用它对来自各种重叠查询的结果进行重复数据删除。
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
【讨论】:
由于反序列化,数组越大越复杂,速度越慢。我使用 array_intersect_key 是有原因的(比这个答案早半年)。 @OIS 刚刚对其进行了很好的测试,有一个错字,但它有效.. 谢谢老兄!: $no_duplicates = array_intersect_key( $array , array_unique( array_map('serialize' , $array ) ) ); 如果你希望索引连续,使用 array_values 即 $input = array_values(array_map("unserialize", array_unique(array_map("serialize", $input)))); 现在您可能会选择 json_encode 和 json_decode 而不是 PHP 序列化。应该对提供的值有好处并且您不会遇到序列化/反序列化附带的 PHP 序列化细节,而且很可能是不需要的。 请注意serialize(array('a' => '1', 'b' => '1'))
与serialize(array('b' => '1', 'a' => '1'))
不同。对于用作sets
或(hash)maps
的数组,此选项将失败。【参考方案4】:
一个易于阅读的解决方案,可能不是最有效的:
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;
【讨论】:
【参考方案5】:我遇到了类似的问题,但我找到了一个 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'));
?>
【讨论】:
这回答了一个不同的问题。见这里:***.com/questions/4585208/… 很棒的功能!如果您正在处理对象: if(!isset($array->$v->$key)) $array[$v->$key] =& $v;【参考方案6】:从 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
)
)
但请记住,the documentation 声明:
array_unique()
不适用于多维数组。
【讨论】:
我想这是比公认的解决方案更快速、更清晰的解决方案!让我们投票给这个! :) 嗯on php site 我们可以看到它并不像我想的那么快...... 奇怪的是,使用 SORT_REGULAR 标志对我不起作用,无法删除重复的数组。 @Stefan 你是对的;它似乎没有给出正确的结果,但它可能是一个错误,因为它works with PHP 7 =/ 这似乎也适用于我的情况,但是还有其他人被 array_unique() 文档中的这个注释所困扰吗? php.net/manual/en/… @Jack 你说得对,这是 PHP 5.6.23 中的一个错误:eval.in/645675,但自 PHP 7.0.8 起已修复:eval.in/645676【参考方案7】:序列化和唯一性的替代方法
$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"
*/
【讨论】:
【参考方案8】:如果您需要消除特定键上的重复项,例如 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 倍。
【讨论】:
【参考方案9】:如果你有这样的数组
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
)
)
你想得到这样的数组:
data = array
(
[0] => array
(
[subject] => a
[object] => c
),
[1] => array
(
[subject] => b
[object] => d
),
[2] => array
(
[subject] => d
[object] => c
)
)
或
data = array
(
[0] => array
(
[subject] => d
[object] => b
),
[1] => array
(
[subject] => c
[object] => a
),
[2] => array
(
[subject] => c
[object] => d
)
)
以下代码可以提供帮助
$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;
【讨论】:
【参考方案10】:我对这个问题进行了深思熟虑,并确定最佳解决方案应遵循两条规则。
-
为了可扩展性,就地修改阵列;不复制到新数组
出于性能考虑,每次比较只能进行一次
考虑到这一点并考虑到 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);
以重新编号键。
【讨论】:
【参考方案11】:正如人们所说的array_unique()
非常慢,这是我用于一级多维数组的sn-p。
$serialized_array = array_map("serialize", $input);
foreach ($serialized_array as $key => $val)
$result[$val] = true;
$output = array_map("unserialize", (array_keys($result)));
参考array_unique()
function page in php.net的第一个用户提供的注释
【讨论】:
Anuj,你能编辑你的答案吗?有一个错误。它应该结束$output = array_map('unserialize', array_keys($result));
@keyboardSmasher 感谢您的意见。我进行了更改,现在它可以工作了。 :)【参考方案12】:
如果你有这样的数组:
(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
【讨论】:
【参考方案13】:如果“删除重复项”的意思是“删除重复项,但保留一个”,解决方案可能是先在“标识符列”上应用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
)
)
【讨论】:
【参考方案14】:很多人问我如何制作唯一的多维数组。我参考了您的评论,这对我有帮助。
首先,感谢@jeromegamez @daveilers 的解决方案。但是每次我给出答案时,他们都会问我“序列化”和“反序列化”是如何工作的。这就是为什么我想和你分享这个的原因,以便帮助更多的人理解这背后的概念。
我正在解释为什么我们在步骤中使用“序列化”和“反序列化”:
第一步:将多维数组转换为一维数组
要将多维数组转换为一维数组,首先要生成数组内部所有元素(包括嵌套数组)的字节流表示。 serialize() 函数可以生成一个值的字节流表示。要生成所有元素的字节流表示,请在 array_map() 函数中调用 serialize() 函数作为回调函数。无论多维数组有多少层,结果都是一维数组。
第 2 步:使值独一无二
要使这个一维数组唯一,请使用 array_unique() 函数。
第三步:还原为多维数组
虽然数组现在是唯一的,但值看起来像字节流表示。要将其恢复为多维数组,请使用 unserialize() 函数。
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
再次感谢这一切。
【讨论】:
【参考方案15】:唯一一个多维数组的一个非常简单且合乎逻辑的方法如下,
如果你有这样的数组:
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
)
)
我希望这会清除一切。
【讨论】:
【参考方案16】: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);
这将从数组中删除重复的名称。按键唯一
【讨论】:
确保$array
的密钥从“0”开始。如果$array
是先前数组操作的结果,则$array
的键可能从另一个数字开始。使用array_values
将密钥重置为“0”【参考方案17】:
根据标记为正确的答案,添加我的答案。添加的小代码只是为了重置索引-
$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
【讨论】:
@milic 6 年前的回答展示了如何用array_values()
包装嵌套函数调用。我认为不需要添加此答案。您可以在接受的答案下添加评论说“如果您想重新索引结果,只需致电 array_values()
”。【参考方案18】:
我已经尝试这样做来删除重复项。
$array = array_map("unserialize", array_unique(array_map("serialize", $array)));
【讨论】:
以上是关于如何从 PHP 中的多维数组中删除重复值的主要内容,如果未能解决你的问题,请参考以下文章