【问题标题】:Finding nested duplicate arrays in JavaScript. (Nested Array uniq in lodash/underscore)在 JavaScript 中查找嵌套的重复数组。 (lodash/下划线中的嵌套数组 uniq)
【发布时间】:2015-01-09 01:09:16
【问题描述】:

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

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

有谁知道确定数组是否包含重复数组的方法?

【问题讨论】:

  • 当你说'重复'时,你的意思是数组是同一个对象,或者数组具有相同的长度和项的顺序,或者具有相同的长度但项的顺序不同?

标签: javascript underscore.js lodash


【解决方案1】:

有点草率,但是(可能)

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

会给你一个正确的结果

【讨论】:

  • 在这个非常简单的例子中,可能取决于 OP 的定义。
【解决方案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 的排序版本

【讨论】:

    【解决方案3】:

    来自underscore.js documentation

    uniq _.uniq(array, [isSorted], [iteratee]) 别名:unique
    产生一个 数组的无重复版本,使用 === 来测试对象 平等。如果您事先知道数组已排序,则传递 isSorted 的 true 将运行更快的算法。如果你想 根据转换计算唯一项,传递一个迭代对象 功能

    但数组在 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”:您最好比较数组的每个值,如this StackOverflow question 中所述。

    通过在该问题中使用建议的equals 实现,您需要实现自己的uniq 版本,该版本使用equals 而不是===

    implementation of uniq in Underscore 非常简单——它创建一个新的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 with all the code,如果你想玩的话。

    【讨论】:

    • 数组可以严格比较,var a=[1,2], b=[1,2]; 现在a===atrue,它们是同一个数组。但是a===bfalse,它们不是同一个数组,但它们都是长度相同且项值顺序相同的数组。要测试它们的项目值是否相等,您应该检查它们的长度,然后逐项检查,是否相同。
    • @Xotic750,当您比较 a === a 时,您不是在将数组与自身进行比较,而是将数组的 reference 与自身进行比较,这显然必须是正确的。实际上,a === a 将永远为真 (jsbin)。您是正确的,检查是否相等的最佳方法是检查每个项目,我将链接到讨论该问题的答案。
    • 然后他们被严格比较,因为它是同一个对象,我确实继续解释了,但也许只是评论还不够清楚。我还向 OP 询问了他的意思。而且a===a 并不总是true,试试var a=NaN, b=NaN。也许你的陈述应该是You can not strictly compare (i.e. === or even ==) 2 different array object for their content
    • 甚至不仅仅是我向 OP 提出的简单问题,您甚至可能需要考虑以下是否被视为相等 var a=[1,2], b={0:1,1:2,length:2},这只是另一个示例
    • 我已经改进了我的问题,以反映转换为字符串并不是解决问题的理想方法。无论如何,我们必须同意它更简单:)
    【解决方案4】:

    在最新的 lodash (4.6.1) 中,你可以这样做:

    if (_.uniqWith(arr, _.isEqual).length < arr.length) {
      // then there were duplicates
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 1970-01-01
      • 1970-01-01
      • 2017-06-15
      • 2017-04-24
      相关资源
      最近更新 更多