查找数组

时间:2016-04-22 04:16:28

标签: javascript arrays underscore.js lodash

给定一个数组数组,识别重复项的有效方法是什么?

var array = [
  [
    11.31866455078125,
    44.53836644772605
  ],
  [                     // <-- Here's the duplicate
    11.31866455078125,
    44.53836644772605
  ],
  [
    11.371536254882812,
    44.53836644772605
  ],
  [
    11.371536254882812,
    44.50140292110874
  ]
]

我一直在使用lodash作为一个公认的依赖关系,我得到了如何返回&#34; unique&#34;列表使用_.uniqWith_.isEqual

_.uniqWith(array,_.isEqual)

随着将给予&#34;独特的&#34;列表的版本:

[ 
    [ 11.31866455078125,  44.53836644772605 ],
    [ 11.371536254882812, 44.53836644772605 ],
    [ 11.371536254882812, 44.50140292110874 ]
]

但是,不仅仅是报告唯一元素,我只需要复制的元素,理想情况下是第一次出现的索引。

lodash库中是否实际涵盖了我错过的一些方法组合?或者我只需要编写循环来比较元素。

可能只是在这方面过度了,所以对这个问题的新观点是值得欢迎的。

如果有适合的库方法,请尽量不重写函数,所以我基本上坚持:

  1. 仅使用&#34;唯一列表&#34;返回重复或至少比较差异。

  2. 基本上确定&#34;&#34;指数&#34;数组中的数组。虽然我认为一旦识别出重复的项目,可以使用_.isEqual减少过滤器。

  3. 还试图避免创建一个对象Hash / Map并在这里计算键的出现次数,或者至少不作为一个单独的对象,以及可以在功能上完成的事情&#34; in-line&#34;

5 个答案:

答案 0 :(得分:5)

Lodash提供了许多有用的功能来实现找到第一个重复索引 使用_.findIndex()_.isEqual()以下代码将找到第一个重复索引:

var duplicateIndex = _.findIndex(array, function(value, index, collection) {
  var equal = _.isEqual.bind(undefined, value);
  return _.findIndex(collection.slice(0, index), equal) !== -1;
});

或者更快但更详细:

var duplicateIndex = _.findIndex(array, function(value, index, collection) {
  var equal = _.isEqual.bind(undefined, value);
  return _.findIndex(collection, function(val, ind) {
     return ind < index && equal(val);
  }) !== -1;
});

请注意,如果不存在重复,则会返回-1 简而言之,算法遍历数组并回顾当前元素是否已经存在。如果是,则返回当前的迭代索引 请检查工作demo

答案 1 :(得分:2)

这是一种使用uniqWith()difference()的方法:

_.indexOf(array, _.head(_.difference(array, _.uniqWith(array, _.isEqual))));

基本理念是:

  1. 使用uniqWith()删除array
  2. 中的重复项
  3. 使用difference()array与无重复版本进行比较。这为我们提供了一系列重复项。
  4. 使用head()获取数组的第一项。这是我们感兴趣的副本。
  5. 使用indexOf()查找副本的索引,在本例中为1
  6. 但是,如果您需要原始的索引,而不是重复,我们必须进行一些调整:

    var duplicate = _.head(_.difference(array, _.uniqWith(array, _.isEqual)));
    _.findIndex(array, _.unary(_.partial(_.isEqual, duplicate)));
    

    我们仍然使用uniqWith()difference()来查找duplicate。但现在,我们正在使用findIndex()来获取索引。原因是我们需要使用isEqual()来查找副本的第一个位置,而不是第二个。我们使用partial()unary()构建谓词。这次的结果是0

答案 2 :(得分:1)

你可以使用普通的&#39; javascript要做到这一点,它并不难,这是我的实现

for (var i = 0; i < array.length; i++) {
  for (var j = i + 1; j < array.length; j++) {

     // quick elimination by comparing subarray lengths
     if (array[i].length !== array[j].length) {
        continue;
     }
     // look for dupes
     var dupe = true;
     for (var k = 0; k < array[i].length; k++) {
       if (array[i][k] !== array[j][k]) {
         dupe = false;
         break;
       }
     }
     // if a dupe then print
     if (dupe) {
         console.debug("%d is a dupe", j); 
     }
   }
 }

关于这个实现的好处是它会打印多次,索引处的数组是多个dupe的欺骗,你可以使用这个事实来计算每个索引中的dupe!

这实际上是一种非常有效的方法,因为内部for循环(j)总是从外循环的下一个位置(i)运行。所以你的支票数量减半。

这是一个plunk

答案 3 :(得分:1)

我不知道如何做到这一点,而不仅仅是自己编写算法。这个答案和其他发布的答案都不是很有效但应该没问题:

function findIndex(array, startingIndex, value) {
  var predicate = _.partial(_.isEqual, value);
  var arraySubset = array.slice(startingIndex+1);
  var index = arraySubset.findIndex(predicate);
  return index === -1 ? index : index+startingIndex+1;
}

function findDuplicates(array) {
  return array.map((value, index) => {
    return {
      value,
      index: findIndex(array, index, value)
    };
  }).filter(info => info.index !== -1);
}

findDuplicates([1, 2, 3, 4, 1, [ 3 ], [ 4 ], [ 3 ] ]);

// [ { value: 1, index: 4 }, { value: [ 3 ], index: 7 } ]    // [ { value: 1, index: 4 }, { value: [ 3 ], index: 7 } ]

这基本上创建了一个数组的映射,在数组的其余部分调用.findIndex(),记下任何重复项的索引,返回有重复项的每个项的信息以及重复项的索引。

关于这一点的一个好处是,它可以适用于三次重复或任何数量的值。

答案 4 :(得分:1)

我认为构建LUT是进行比较时最有效的方法之一。下面的方法利用Array.prototype.reduce()构造一个LUT,并最终通过删除一个而不是所有重复的元素来改变原始数组,而不管它们有多少。

&#13;
&#13;
var arr = [
  [
    11.31866455078125,
    44.53836644772605
  ],
  [
    11.31866455078125,
    44.53836644772605
  ],
  [
    11.371536254882812,
    44.53836644772605
  ],
  [
    11.371536254882812,
    44.50140292110874
  ]
];
arr.reduce((p,c,i)=> { var prop = c[0]+"" + c[1]+"";
                       p[prop] === void 0 ? p[prop] = i : p.dups.push(i);
                       return p;
                     },{dups:[]}).dups.reverse().forEach( i => arr.splice(i,1))

document.write('<pre>' + JSON.stringify(arr, 0, 2) + '</pre>');
&#13;
&#13;
&#13;

但是如果你希望通过保留原始数据来获得一个新阵列,那么显然会更快一些。