JavaScript数组与关联数组的区别

4
有没有一种方法可以在JavaScript中返回两个数组之间的差异?在这种情况下,我无法使用indexOf。
例如:
var a1 = [{"a":"A"},{"b":"B"}];
var a2 = [{"a":"A"},{"b":"B"},{"c":"C"}];

// need [{"c":"C"}]

请给予建议。

3
严格来说,“差异”是指整个数组,因为只有当两个对象引用同一实例时它们才相等,而这些字面量并不是如此。 - Niet the Dark Absol
4个回答

2
正如我在评论中提到的,只有当对象引用同一实例时才相等。因此,任何内置系统都不会做到这一点,尤其是=====。所以,首先你必须定义自己的比较函数。
假设两个对象包含相同的键和相同的值,则它们相等。
function areObjectsEqual(a,b) {
    function helper(a,b) {
        var k;
        for( k in a) {
            if( a.hasOwnProperty(k)) {
                if( !b.hasOwnProperty(k)) return false;
                if( typeof a[k] != typeof b[k]) return false;
                if( typeof a[k] == "object") {
                    if( !areObjectsEqual(a[k],b[k])) return false;
                    // the above line allows handling of nested objects
                }
                else {
                    if( a[k] != b[k]) return false;
                    // this comparison is technically strict
                    // because we already checked typeof earlier
                }
            }
        }
    }
    return helper(a,b) && helper(b,a);
}

好的,既然这件事处理完了,我们可以比较一下我们的函数。

function array_diff(a,b) {
    var result = [], l = a.length, i, m = b.length, j;
    outer:
    for( i=0; i<l; i++) {
        for( j=0; j<m; j++) {
            if( typeof a[i] != typeof b[j]) continue;
            if( typeof a[i] == "object") {
                if( !areObjectsEqual(a[i],b[j])) continue;
            }
            else {
                if( a[i] != b[j]) continue;
            }
            // if we got to here, it's a match!
            // ... so actually we want to skip over the result :p
            continue outer;
        }
        // okay, if we get HERE then there was no match,
        // because we skipped the "continue outer"
        result.push(a[i]);
    }
    return result;
}

好的,没问题!


你需要在areObjectsEqualarray_diff检查上添加一个闭合括号。 - Ian Clark
最好在array_diff函数的结尾返回result,但这样也不能得到正确的答案。 - Ian Clark
我可能在某个地方出错了...我不知道。现在还太早了!XD 但是请确保先传递更长的数组——此函数返回a中不在b中的所有元素。 - Niet the Dark Absol
哈哈!那么,目前我的看法是:我喜欢这种方法,我认为它很易读。我不确定你为什么要检查 typeof 然后使用松散相等,而不是最初进行无类型转换的检查(也许是速度的区别?),我也不喜欢 array_diff 中的变量名,阅读起来很难受。除此之外,干得好! :) - Ian Clark
@IanClark 因为在对象上使用===不好。所以我首先检查类型,显然如果它们不同,我们可以拒绝。如果类型相同,则根据该类型是object还是其他类型来处理比较的方式会有所不同。 - Niet the Dark Absol

2

即使两个对象具有相同的内容,它们也永远不可能完全相同。它们仍然是不同的对象实例。

这意味着您必须比较键和值以检查它们是否匹配,或者在这种情况下,不匹配。

var a1 = [{"a":"A"},{"b":"B"}];
var a2 = [{"a":"A"},{"b":"B"},{"c":"C"}];

var a3 = a2.filter(function(o) {
    return Object.keys(o).some(function(k) {
        return a1.every(function(o2) {
            return !(k in o2) || (o2[k] != o[k]);
        });
    });
});

FIDDLE


@Johan - 是的,对于具有大数组的集合来说,这可能不是最好的选择,但我没有看到比仅迭代所有对象更好的比较方法。 - adeneo

0
var a1 = [{"a":"A"},{"b":"B"}];
var a2 = [{"a":"A"},{"b":"B"},{"c":"C"}];
var obj = {}, result = [];

function updateObjectCount(currentItem) {
    var keys, key;
    for (key in currentItem) {
        if (currentItem.hasOwnProperty(key)) {
            keys = key;
            break;
        }
    }
    obj[key] = obj[key] || {};
    obj[key][currentItem[key]] = (obj[key][currentItem[key]] || 0) + 1;
}

a1.forEach(updateObjectCount);
a2.forEach(updateObjectCount);

for (var key1 in obj) {
    if (obj.hasOwnProperty((key1))) {
        for (var key2 in obj[key1]) {
            if (obj.hasOwnProperty((key1))) {
                if (obj[key1][key2] === 1) {
                    var temp = {};
                    temp[key1] = key2;
                    result.push(temp)
                }
            }
        }
    }
}

console.log(result);
# [ { c: 'C' } ]

0

轻松简单地实现您的目标

var a1 = [{"a":"A"},{"b":"B"}];
var a2 = [{"a":"A"},{"c":"C"},{"b":"B"}];

var max = (a1.length > a2.length) ? a1 : a2;
var min = (a1.length > a2.length) ? a2 : a1;
var newArray = [];

for ( var i = 0; i < max.length; i++ ) { // saving elements into string
    max[i] = JSON.stringify(max[i]);
    if ( typeof min[i] !== undefined ) {
        min[i] = JSON.stringify(min[i]);
    }
}

for ( var i = 0; i < max.length; i++ ) { // checking values uniqueness
    if ( min.indexOf(max[i]) === -1 ) {
        newArray.push(max[i]);
    }
}

// if you need new Array's elements back in object do following iteration
for ( var i in newArray ) { // loop recreate results array's elements into object again
    newArray[i] = JSON.parse(newArray[i]);
}

console.log(newArray); // result : [Object { c="C"}]

{{link1:JSFiddle}}


这正是我所想的,但如果相等的元素在数组中具有不同的索引,则它无法正常工作。否则从理论上讲这些项将不相等......或者会吗?我不知道。 - VisioN
@VisioN,它可以工作,你知道为什么吗?因为我已经定义了“max”和“min”变量,如果某些索引缺失,则无关紧要,因为“max”将保留具有更多元素的数组,即使有任何东西丢失。 - nanobash
@VisioN 在循环中,如果缺少一些索引,也不会影响最终结果 :) - nanobash
@crypticous - 我认为他的意思是这个彻底失败了 - adeneo
@VisioN,我变得非常好奇,你说的是什么意思,能具体一些吗?是什么不能或不会工作? - nanobash
1
@crypticous - 没有人说你应该猜测什么,但如果数组的顺序不完全相同,它就会失败,因此它并没有真正比较对象,而是比较了两个数组,即使最微小的差异也会导致失败。 - adeneo

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