JavaScript:比较三个数组

6

我希望能够比较多个数组,并将其中相同的数组合并:

A = [1,2,3];
B = [1,2,3];
C = [1,2,3];

D = [10,11,12];
E = [10,11,12];
F = [10,11,12];

G = [13,14];
H = [13,14];

如果有相同的数组,我希望可以创建新的数组来存储这些相同的数组:

I = [1,2,3];
J = [10,11,12];
K = [13,14];

我需要逐个遍历一个数组中的每个元素并将其与其他数组中的所有元素进行比较吗?
for (var i in A) {
    for (var j in B) {
        if (A[i] == J[j]) {
            // create new arrays
        }
    }
}

那么,将匹配项创建为新数组吗?听起来开销很大。

最佳的解决方法是什么?

谢谢!


for-in循环遍历对象键。它不是for-each循环,您不应在数组上使用它。 - hugomg
@missingno 的评论很好,但请尝试解释为什么不应该使用某些东西或提供链接。谢谢。 - JsusSalv
我应该更明确地说明。除了索引属性(你真正关心的那些属性)之外,数组还有其他属性,而 for-in 循环也可以迭代它们(除非你的浏览器完全保护你不受其影响)。如果将来决定使用更改 Array.prototype 的库(例如 MooTools 或 Prototype),那么突然间会出现大量的杂项循环,这是特别危险的。要迭代数组,您应该使用普通的 for-loop 或其中的一个迭代方法,如 .forEach(如果您的浏览器/库支持)。 - hugomg
6个回答

6

如果您只是想完成唯一数组,我建议使用哈希表方法:

var myArrays = [A,B,C,D,E,F,G],
    uniques = [],
    hashes = {};

for (var i=0; i < myArrays.length; i++) {
    var hash = JSON.stringify(myArrays[i]); // or .toString(), or whatever
    if (!(hash in hashes)) {
        hashes[hash] = true;
        uniques.push(myArrays[i]);
    }
}
// uniques now holds all unique arrays

除了一个场景外,仍然存在一些问题。有点疯狂,但事实就是这样。你能提供一个有效的 jsFiddle 示例吗? - JsusSalv
这是链接:http://jsfiddle.net/nrabinowitz/L4Ekx/1/。我的`for`循环中有一个错别字 - var i; 应该是 var i=0;。已经更正。 - nrabinowitz
在进行各种测试后,我必须说这个非常好用!为了让JSON.stringify与传统浏览器兼容,我只需要添加Douglas Crockford的JSON-js迷你库。我调用了json2.js文件,一切都很完美,特别是在IE 6/7中:https://github.com/douglascrockford/JSON-js - JsusSalv
如果我能为你的答案添加更多积分,我一定会这样做!谢谢 :) - JsusSalv
1
很高兴这对你有用!JSON.stringify 可能是最好的哈希函数,但如果你知道你的数组只包含数字或字符串,那么你也可以使用简单的 .toString() - nrabinowitz

2

根据你对“相同”的定义,你可以将其转换为字符串并进行比较。

if (A.toString() == B.toString()) { //combine }

1

嗯...我会这样做

function combine(arr1, arr2)
{
    if(arr1.join(',') === arr2.join(','))
        return arr1;
}

或者对于许多数组

function combine(arrList)
{
    var pass = true;
    var compareArray = arrList[0];
    for(var i in arrList)
        pass = pass && (arrList[i].join(',') === compareArray.join(','));
    if(pass)
        return compareArray;
}

arr = combine([[1,2,3],[1,2,3],[1,2,3]]); // results in [1,2,3]

@nrabinowitz 我不明白它与列出的任何其他方法有什么不同。即使在你的方法中,它也会循环与数组一样多的次数。唯一的区别是你的方法将它们存储在一个对象中。你的方法还有可能进行多个比较(散列中的哈希部分),使其触及比存在的数组数量更多的数组(例如,对于5个数组,它可能进行8次比较)。在那种情况下,我的方法只会进行5次比较,甚至可以优化为4次比较。 - Joseph Marikle
我只是比较哈希值,而不是数组。我的版本是O(n) - 对于5个数组,它会进行5次哈希查找。也许我对你的版本有所遗漏 - 我只是没有看到你的方法如何将一个数组列表转换为唯一数组列表,这正是OP想要的。 - nrabinowitz
我认为这个解决方案不正确;它只是检查第一个数组是否等于所有其他数组,如果是,则返回该第一个数组。 - Peter
@Peter 这就是 OP 请求的内容。目标是合并相同的数组。您可以将它们作为字符串进行比较,如果它们相同,则合并没有实际意义。您只需返回第一个即可。 - Joseph Marikle
@Joseph - 是的,但如果你想要所有独特的数组(我认为这是OP想要的),你需要对序列中的每个数组运行此操作,并与其他每个数组进行比较。 - nrabinowitz
@Joseph,举个例子,我的理解是这个输入:[[1,2,3], [1,2,3], [4,5]] 应该返回 [[1,2,3], [4,5]]。而你的解决方案将返回 undefined。看起来你的解决方案只是验证每个输入数组是否完全相同。 - Peter

1

如果你只是比较原始数组 - 数字或字符串,那么可以比较它们的字符串表示。

function simpleArrayMatch(A,B){
    return String{A)===String(B);
}

我对这个函数很好奇。你能更详细地解释一下,以便让我了解它的工作上下文吗? - JsusSalv
没有jsFiddle示例?对于一个数组集合运行良好,但对于多个呢? - JsusSalv

1
假设每个数组中都只有数字或文本,那么这可能是一种可行的方法,而无需循环遍历任何数组:
(请参见此处的fiddle here
代码:
A = [1,2,3];
B = [1,2,3];
C = [1,2,3];

D = [10,11,12];
E = [10,11,12];
F = [10,11,12];

G = [13,14];
H = [13,14];

function compareArr(arrList){
    var S = '@' + arrList.join('@');
    var re = /(@[^@]+)(@.*)?(\1)(@|$)/gi
    var afterReplace=''; var i=0;
    while(afterReplace!=S && i<100){
        afterReplace=S;
        S = S.replace( re, "$1$2$4" )
        i++
    }

    return S.substr(1,S.length-1).replace(/@/g,'<br>')
}

$('html').append( compareArr([A,B,C,D,E,F,G,H]) )

策略是将所有数组连接成一个字符串,使用“@”作为分隔符。然后使用正则表达式替换字符串中的所有重复部分,最后拆分字符串,您就得到了唯一数组的列表。

我在代码中使用while循环的原因只是因为我无法编写更好的正则表达式模式一次性删除重复部分。寻找更好的正则表达式?


0
我相信是这样的,但至少你可以使用一个比较数组函数来使它更容易,即使速度可能会慢一些。
function compareArrays(arr1,arr2)
{
    if (arr1.length != arr2.length) return false;
    for (var i = 0; i < arr2.length; i++) 
    {
        if (arr1[i].compareArrays) 
        { //likely nested arr2ay
            if (!arr1[i].compareArrays(arr2[i])) return false;
            else continue;
        }
        if (arr1[i] != arr2[i]) return false;
    }
    return true;
}

然后,你只需要在遍历数组时使用这个函数。


我想指出,我从其他地方得到了这个函数,可能是在Stackoverflow上,但我早已忘记了它的来源。 - Deets McGeets

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