在JavaScript中查找嵌套的重复数组。(lodash/underscore中的嵌套数组去重)

3

我正在尝试确定一个JavaScript数组的数组是否包含重复项。这可能吗?我首先尝试查看是否可以去除重复项,然后进行相等性检查,但我无法通过第一部分。这是underscore返回的内容:

var arr1 = [[1,2], [2,3], [1,2]];
var arr2 = _.uniq(arr1);

var arraysAreEqual = _.isEqual(arr1, arr2);

console.log(arraysAreEqual, arr1, arr2);
// true

Jsbin: http://jsbin.com/vogumo/1/edit?js,console

有人知道如何确定数组是否包含重复的数组吗?


当你说“重复”时,是指数组是相同的对象,还是指数组具有相同的项目长度和顺序,或者具有相同的长度但不具有项目顺序? - Xotic750
4个回答

2

它有点懒散,但可能是(可行的)

var arr2 = _.uniq(arr1, function(item) {
    return JSON.stringify(item);
});

会为您提供正确的结果


在这个非常简单的例子中,也许取决于OP的定义。 - Xotic750

2

根据underscore.js文档:

uniq _.uniq(array, [isSorted], [iteratee]) 别名: unique
制作一个无重复的数组版本,使用===来测试对象的相等性。如果你事先知道数组是排序过的,传入true给isSorted将运行更快的算法。如果要基于一个转换计算独特的项,则传递迭代器函数

但在JavaScript中,数组不能严格比较。

因此,您可以使用转换函数使uniq能够进行比较。例如:

console.log([1,2] === [1,2]) // false, can't strict compare arrays
console.log([1,2].toString()) // "1,2" - string representation
console.log([1,2].toString() === [1,2].toString()) // true, strings can be compared

var valueToString = function(v) {return v.toString()}; // transform array to string
var arr1 = [[1,2], [2,3], [1,2]];
var arr2 = _.uniq(arr1, false, valueToString); // compare based on transformation
var arraysAreEqual = _.isEqual(arr1, arr2);

console.log("arraysAreEqual:", arraysAreEqual, arr1, arr2); 
// false
// [[1, 2], [2, 3], [1, 2]]
// [[1, 2], [2, 3]]

请注意,将数组转换为字符串是“hacky”的做法:最好比较数组的每个值,如此StackOverflow问题中所讨论的那样。
通过使用该问题中提出的equals实现,您需要实现自己的uniq版本,该版本使用equals而不是===
Underscore中uniq实现非常简单 - 它创建一个新的result数组并循环遍历给定数组。如果当前值尚未在结果中,则插入它。
console.log("Using array comparison:");
arrayEquals = function (array1, array2) {
    // if any array is a falsy value, return
    if (!array1 || !array2)
        return false;

    // compare lengths - can save a lot of time 
    if (array1.length != array2.length)
        return false;

    for (var i = 0, l=array1.length; i < l; i++) {
        // Check if we have nested arrays
        if (array1[i] instanceof Array && array2[i] instanceof Array) {
            // recurse into the nested arrays
            if (!arrayEquals(array1[i],array2[i]))
                return false;       
        }           
        else if (array1[i] !== array2[i]) { 
            return false;   
        }        
    }       
    return true;
};

_.uniqArrays = function(array) {
  if (array == null) return [];
  var result = [];
  for (var i = 0, length = array.length; i < length; i++) {
    var value = array[i];
    var arrayEqualsToValue = arrayEquals.bind(this, value); // arrayEquals with first argument set to value
    var existing = _.find(result, arrayEqualsToValue); // did we already find this?
    if (!existing) {
      result.push(value);
    }
  }
  return result;
};

var arr3 = _.uniqArrays(arr1);
arraysAreEqual = _.isEqual(arr1, arr3);
console.log("arraysAreEqual:", arraysAreEqual, arr1, arr3); // false

如果您想尝试一下,我已经在jsbin上放置了所有代码


数组可以进行严格比较,例如 var a=[1,2], b=[1,2]; 现在 a===atrue,它们是同一个数组。但是 a===bfalse,它们不是同一个数组,但它们都是长度和项目值顺序相同的数组。要测试它们的项目值是否相等,则应检查它们的长度,然后逐个检查项目,无论顺序如何。 - Xotic750
1
@Xotic750,当你比较a === a时,你并不是在比较数组本身,而是在比较数组的引用是否相等,这显然是正确的。实际上,a === a总是为真(jsbin)。你说得对,检查每个元素的相等性是最好的方法,我会链接到一个讨论这个问题的答案。 - Guilherme Rodrigues
1
然后它们被严格比较,因为它们是同一个对象,我继续解释了一下,但也许只是一个评论,不够清楚。我还询问了OP关于他的意思。而且a === a并不总是true,尝试var a = NaN,b = NaN。也许你的陈述应该像这样:您不能严格比较(即===或甚至==)两个不同的数组对象以获取其内容 - Xotic750
甚至比我问的那个简单问题更重要的是,你甚至需要考虑以下是否被视为相等:var a=[1,2], b={0:1,1:2,length:2},这只是另一个例子。 - Xotic750
1
我已经修改了我的问题,以反映将其转换为字符串并不是解决方案的最佳方法。无论如何,我们必须同意它更简单 :) - Guilherme Rodrigues
实际上,已经有一个被广泛认可的等价断言测试(也称为deepEqual),这可能适合OP的需求,但谁知道呢。 - Xotic750

2

试一下这个:

var numArray = [1, 7, 3, 0, 9, 7, 8, 6, 2, 3];
var duplicates = [];
var sortednumArray = numArray.sort();


for (var i = 0; i < sortednumArray.length; i++) {
    //console.log(sortednumArray[i]);
    if (sortednumArray[i] == sortednumArray[i + 1]) {
        duplicates.push(sortednumArray[i]);
    }
}

if (duplicates.length == 0) {
    console.log("Soted Array:");
    for(var i = 0; i < sortednumArray.length; i++) {
        console.log(sortednumArray[i]);
    }
} else {
    console.log("Duplicates:");
    for(var i = 0; i < duplicates.length; i++){
        console.log(duplicates[i]);
    }
}

程序将所有重复项推送到名为“duplicates”的数组中,然后显示它,但如果没有重复项,则显示numArray的排序版本。请保留HTML标签。

1
在最新的lodash(4.6.1)中,您可以这样做:
if (_.uniqWith(arr, _.isEqual).length < arr.length) {
  // then there were duplicates
}

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