Javascript -- 比较两个数组,返回差异,但有一个问题

7
我找到了很多解决这个问题的帖子:
假设我们有:
array1 = ['A', 'B', 'C', 'D', 'E']; array2 = ['C', 'E'];

有没有一种经过验证且快速的解决方案,可以比较两个数组,返回一个数组,其中不包含两个数组中都存在的值(在此处为C和E)?期望的解决方案是:
array3 = ['A', 'B', 'D']

但是如果你有:
array1 = ['A', 'B', 'C', 'D', 'D', 'E']; array2 = ['D', 'E'];

"你正在寻找解决方案为:"
array3 = ['A', 'B', 'C', 'D'] // don't wipe out both D's

这是一些上下文:
你正在教学生如何理解句子结构。你给他们一个打乱的句子:
ate -- cat -- mouse -- the -- the 他们开始输入答案:The cat。
现在,你希望提示信息显示为:
ate -- mouse - the 目前,我的代码将两个 "the" 都删除了。
以下是我尝试过的方法: (zsentence 是 xsentence 的副本,将被代码操作、join() 以及输出到屏幕)
for (i=0; i < answer_split.length; i++) {
for (j=0; j < xsentence.length; j++) {
        (function(){
            if (answer_split[i] == xsentence[j]) { zsentence.splice(j,1); return; }
        })();
    }
}

2
匿名函数和return语句有什么作用?据我所知,它们都没有任何作用。 - John Kugelman
@JohnKugelman 匿名函数是一个自调用函数,因此它会执行某些操作。另一方面,return 是无用的。 - Matt Ball
@MattBall 我的意思是为什么要将 if 语句包装在匿名函数中。这并没有增加任何东西。 - John Kugelman
在这种情况下 - 是真的。我猜这是对this pattern的误用。 - Matt Ball
2个回答

16

只需遍历您想要删除的元素数组即可。

var array1 = ['A', 'B', 'C', 'D', 'D', 'E'];
var array2 = ['D', 'E'];
var index;

for (var i=0; i<array2.length; i++) {
    index = array1.indexOf(array2[i]);
    if (index > -1) {
        array1.splice(index, 1);
    }
}

对于相当小的数组和现代硬件,时间复杂度为O(array1.length * array2.length),通常情况下不会造成问题。

http://jsfiddle.net/mattball/puz7q/

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/splice


1
这很好。你的示例数组已排序。如果是这种情况,你可以使用二分查找来加速。http://en.wikipedia.org/wiki/Binary_search#Deferred_detection_of_equality,“如果键不唯一,则返回最小索引”。 - brianchirls
谢谢Matt。那个.indexOf部分正是我正在寻找的。 - Brad Thomas
在这个解决方案中,您将无法确定array2更长或包含例如“F”和“G”的情况。 - badunk
抱歉,我一直以为是在比较两个数组的差异,但我想在这种情况下,一个数组始终是另一个数组的子集。 - badunk
@badunk 无论如何,你提到的情况并不会引起问题。你为什么认为它可能会呢?http://jsfiddle.net/mattball/3zp66/ - Matt Ball
@MattBall 抱歉,一开始我误读了问题,以为它适用于我自己的情况,我想要比较 [a, b, c, d] 和 [c, b, e, f] ,返回 [a]、[b, c] 和 [e, f]。 - badunk

8
您也可以使用过滤器。请查看下面的示例。
var item = [2,3,4,5];
var oldItems = [2,3,6,8,9];
oldItems = oldItems.filter(n=>!item.includes(n))

所以这将返回[6,8,9]

如果你只想得到匹配的项,那么你必须编写以下代码。

oldItems = oldItems.filter(n=>item.includes(n))

这将仅返回[2,3]。

2
我建议使用oldItems.filter(n => item.includes(n)); 在我看来,这比被接受的答案更可取。没有突变,代码更清晰。 - milesaron
感谢 @milesaron! - Ashish Bhanderi
变量array1 = [1,-7,8,0,9]; 变量array2 = [0,-15,-7,1,8,9]; 变量oldItems = array1.filter(n=>!array2.includes(n));//输出: [] 变量oldItems = array2.filter(n=>!array1.includes(n));//输出: [-15]请问您能否编写一个解决这两种情况的代码? - bhaRATh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接