Php 使用数组_diff时保留副本

Php 使用数组_diff时保留副本,php,arrays,Php,Arrays,我正在使用array_diff()从array1中获取在array2中找到的值。问题在于,正如PHP文档所指出的那样,它删除了array1中的所有事件。我希望它一次只能取出一个 $array1 = array(); $array1[] = 'a'; $array1[] = 'b'; $array1[] = 'a'; $array2 = array(); $array2[] = 'a'; 它应该返回一个包含一个'a'和一个'b'的数组,而不是只包含'b'的数组 编写一些函数,逐个从第一个数组中

我正在使用array_diff()从array1中获取在array2中找到的值。问题在于,正如PHP文档所指出的那样,它删除了array1中的所有事件。我希望它一次只能取出一个

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

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

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

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

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

只是为了好玩,一些刚刚浮现在我脑海里的东西。只要数组包含字符串,就可以工作:

$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]--;
});
它的优点是只在每个阵列上运行一次

工作原理:

首先,计算第二阵列中每个元素的频率。这为我们提供了一个数组,其中键是应该从
$a
中删除的元素,值是每个元素应该删除的次数

然后使用
array\u filter
逐个检查
$a
的元素,并删除那些应该删除的元素。如果没有与正在检查的项目相等的键,或者如果该项目的剩余删除计数已达到零,则过滤器函数使用
empty
返回
true
empty
的行为完全符合要求


如果以上两项都不成立,那么我们希望返回
false
,并将删除计数减少1。使用
false | |$计数[$o]-
是一个技巧,为了简洁起见:它减少计数并始终计算为
false
,因为我们知道计数从一开始就大于零(如果不大于零,
|
将在计算
后短路)。

array_unique()返回一个没有重复值的数组。我要做的是减去两个数组。array_diff()可以执行此操作,但并不精确。谢谢,这是我一直在寻找的。此代码中有一个bug$pos将在$array1中$array2中的项目第一次不匹配时(本例未包括在示例中),然后返回false,在unset()调用中,该值将被强制转换为整数零,从而导致unset($array1[0])。换句话说,这有一个非常严重的缺陷,如果$array2中有一个元素在$array1中不存在,那么$array1的第一个元素将不会被考虑用于数组差异结果,这导致了我的生产代码中有一个非常严重的错误,因为我盲目地复制和粘贴了它,这是相当不明显的。是的,事实上,我编辑了两次我的帖子来包含你的补丁:)。一次用于
array\u count\u值
,一次用于
array\u过滤器
。但仍然比上面的O(N^2)更有效。@SébastienRenauld:每个都有一次,当然,当迭代
$a
时,它会进行一些哈希查找。但即便如此,它仍然是O(N+M)。@sébastienRenauld:别担心。:-)