使用 array_diff 时保持重复
Posted
技术标签:
【中文标题】使用 array_diff 时保持重复【英文标题】:Keep Duplicates while Using array_diff 【发布时间】:2013-06-03 03:02:49 【问题描述】:我正在使用 array_diff() 从 array1 中取出在 array2 中找到的值。问题是它会从 array1 中删除所有出现的事件,正如 php 文档所指出的那样。我希望它一次只取出一个。
$array1 = array();
$array1[] = 'a';
$array1[] = 'b';
$array1[] = 'a';
$array2 = array();
$array2[] = 'a';
它应该返回一个包含一个'a'和一个'b'的数组,而不是一个只有'b'的数组;
【问题讨论】:
array_unique() 返回一个没有重复值的数组。我想要做的是减去两个数组。 array_diff() 会这样做,但并不准确。 【参考方案1】:编写一些函数,从第一个数组中逐个删除元素,例如:
function array_diff_once($array1, $array2)
foreach($array2 as $a)
$pos = array_search($a, $array1);
if($pos !== false)
unset($array1[$pos]);
return $array1;
$a = array('a', 'b', 'a', 'c', 'a', 'b');
$b = array('a', 'b', 'c');
print_r( array_diff_once($a, $b) );
【讨论】:
谢谢,这就是我要找的。span> 这段代码有一个错误。 $pos 将在 $array1 中的 $array2 中的项目第一次不匹配时(这种情况不包括在示例中),然后将返回 false,在 unset() 调用中,它将被强制转换为整数零,导致未设置($array1[0])。换句话说,这有一个非常严重的缺陷,如果 $array2 中有一个元素在 $array1 中不存在,那么 $array1 的第一个元素将不会被视为数组差异结果,这导致了我的生产代码中有一个非常严重的错误,因为我盲目地复制和粘贴了它,相当不明显。 是的,确实,我编辑了我的帖子以包含您的修复:)【参考方案2】:只是为了好玩,刚想到的东西。只要您的数组包含字符串就可以工作:
$a = array('a','b','a','c');
$b = array('a');
$counts = array_count_values($b);
$a = array_filter($a, function($o) use (&$counts)
return empty($counts[$o]) || !$counts[$o]--;
);
它的优点是它只遍历每个数组一次。
See it in action。
工作原理:
首先计算第二个数组中每个元素的频率。这为我们提供了一个数组,其中键是应从 $a
中删除的元素,值是应删除每个元素的次数。
然后array_filter
用于对$a
的元素一一检查,并删除应该删除的元素。过滤器函数使用empty
返回true
,如果没有与正在检查的项目相等的键或者如果该项目的剩余删除计数已达到零; empty
的行为完全符合要求。
如果以上都不成立,那么我们想要返回 false
并将删除计数减一。使用false || !$counts[$o]--
是为了简洁起见:它会减少计数并始终计算为false
,因为我们知道计数一开始就大于零(如果不是,||
会短路在评估empty
)。
【讨论】:
两次。一次用于array_count_values
,一次用于array_filter
。仍然比上面的效率更高,虽然是 O(N^2)。
@SébastienRenauld:每个一次,当然,它在迭代$a
时会进行一些哈希查找。但即便如此,它仍然是 O(N+M)。
@SébastienRenauld:不用担心。 :-)以上是关于使用 array_diff 时保持重复的主要内容,如果未能解决你的问题,请参考以下文章
PHP 使用get_class_methods()和array_diff() 兩個相同的類中方法差集
php array_intersect() 和 array_diff() 函数
为啥 array_diff() 给出数组到字符串的转换错误?