使用array_diff时保留重复项

时间:2013-06-06 22:35:01

标签: php arrays

我正在使用array_diff()从array1中的array1中获取值。问题是它会从array1中删除所有出现的内容,正如PHP文档所记录的那样。我希望它一次只取出一个。

$array1 = array();
$array1[] = 'a';
$array1[] = 'b';
$array1[] = 'a';

$array2 = array();
$array2[] = 'a';

它应该返回一个数组,其中包含一个' a'和一个'而不是只有' b'的数组;

2 个答案:

答案 0 :(得分:11)

只是为了它的乐趣,一些刚想到的东西。只要您的数组包含字符串,就可以工作:

$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,因为我们知道计数开始时大于零(如果不是,{{1在评估||)之后会发生短路。

答案 1 :(得分:5)

编写一些从第一个数组中逐个删除元素的函数,如:

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