Map / Set维护唯一的数组数组,Javascript

时间:2017-05-04 01:15:00

标签: javascript arrays filter set unique

我正在尝试构建唯一的数组数组,这样每当我有新数组添加它时,只应添加它,如果它不存在于集合中

E.g。存储[1,1,2]

的所有唯一排列

实际:[[1,1,2],[1,2,1],[1,1,2],[1,2,1],[2,1,1],[2,1,1]]
预期:[[1,1,2],[1,2,1],[2,1,1]]

我试过的方法:

  1. Array.Filter :不起作用,因为数组是对象,uniqueArrComparer中的每个值都是对该数组元素的唯一对象引用。
  2. function uniqueArrComparer(value, index, self) {
      return self.indexOf(value) === index;
    }
    
    result.filter(uniqueArrComparer)
    
    1. 设置/映射:我认为我可以构建一个独特的数组,但它不起作用,因为Set内部使用严格相等比较器(===),它将考虑每个在这种情况下,数组是唯一的 We cannot customize object equality for JavaScript Set

    2. 将每个数组元素作为字符串存储在Set / Map / Array中,并构建一个唯一字符串数组。在最后使用唯一字符串数组构建数组数组。这种方法可行,但看起来不是有效的解决方案。

    3. 使用Set

      的工作解决方案

      
      
      let result = new Set();
      
      // Store [1,1,2] as "1,1,2"
      result.add(permutation.toString());
      
      return Array.from(result)
        .map(function(permutationStr) {
      
          return permutationStr
            .split(",")
            .map(function(value) {
      
              return parseInt(value, 10);
            });
        });
      
      
      

      这个问题比任何应用程序问题更像是一种学习练习。

5 个答案:

答案 0 :(得分:7)

一种方法是将数组转换为JSON字符串,然后使用Set获取唯一值,然后再转换回来



var arr = [
  [1, 1, 2],
  [1, 2, 1],
  [1, 1, 2],
  [1, 2, 1],
  [2, 1, 1],
  [2, 1, 1]
];

let set  = new Set(arr.map(JSON.stringify));
let arr2 = Array.from(set).map(JSON.parse);

console.log(arr2)




答案 1 :(得分:0)

为了解决每个数组作为唯一对象的问题,您可以对其进行字符串化,使其不再唯一,然后将其映射回数组。这应该可以解决问题:

var arr = [
  [1, 1, 2],
  [1, 2, 1],
  [1, 1, 2],
  [1, 2, 1],
  [2, 1, 1],
  [2, 1, 1]
];


var unique = arr.map(cur => JSON.stringify(cur))
  .filter(function(curr, index, self) {
    return self.indexOf(curr) == index;
  })
  .map(cur => JSON.parse(cur))

console.log(unique);

答案 2 :(得分:0)

您可以将Set子类化,以通过存储对添加的对象调用JSON.stringify的结果来更灵活地存储对象。

class ObjectSet extends Set{
  add(elem){
    return super.add(typeof elem === 'object' ? JSON.stringify(elem) : elem);
  }
  has(elem){
    return super.has(typeof elem === 'object' ? JSON.stringify(elem) : elem);
  }
}
let set = new ObjectSet([[1,1,2],[1,2,1],[1,1,2],[1,2,1],[2,1,1],[2,1,1]]);
console.log([...set]);
console.log([...set].map(JSON.parse));//get objects back

答案 3 :(得分:0)

如果可以使用库,请尝试lodash uniqWith。这将使用您选择的比较器(在您的情况下为等于)递归地找到数组或对象的

var arrayofarrays = [ [1,1,2], [1,2,1], [1,1,2], [1,2,1], [2,1,1], [2,1,1] ]

const uniqarray = _.uniqWith(arrayofarrays, _.isEqual);

console.log(uniqarray) //=> [[1, 1, 2], [1, 2, 1], [2, 1, 1]]

奖金:它也适用于对象数组

var objects = [{ 'x': 1, 'y': {b:1} }, { 'x': 1, 'y': {b:1} }, 
               { 'x': 2, 'y': {b:1} }, { 'x': 1, 'y': 2 }     ];

const uniqarray = _.uniqWith(objects, _.isEqual);

console.log(uniqarray) 
// => [{x: 1, y: {b: 1}}, {x: 2, y: {b: 1}}, {x: 1, y: 2}]

答案 4 :(得分:0)

我发现最快的方法是:

const points = [
  [0,0],
  [100,100],
  [400,400],
  [200,200],
  [200,200],
  [200,200],
  [300,300],
  [400,400],
]

const uniquePoints = Array.from(
  new Map(points.map((p) => [p.join(), p])).values()
)

该线程中的所有方法都很快。然而,这个方法比 Set 方法更快,因为我们永远不需要将字符串化的数组转换回数组。

要查找唯一对象,请将 p.join() 替换为 JSON.stringify(p)

注意

就我而言,上面显示的方法被证明是错误的策略,因为我只需要检查相同的相邻点。例如,上面使用的测试数组包含值 [400,400] 两次,但这些值不连续。上面显示的方法会删除第二个实例,而下面的代码会保留它。

points = points.filter(
    (point, i) =>
      i === 0 ||
      !(points[i - 1][0] === point[0] && points[i - 1][1] === point[1])
  )