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

问题描述 投票:0回答:6

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

例如存储 [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
    中的每个值都是对该数组元素的唯一对象引用。
function uniqueArrComparer(value, index, self) {
  return self.indexOf(value) === index;
}

result.filter(uniqueArrComparer)
  1. Set/Map:以为我可以构建一个唯一的数组集,但它不起作用,因为 Set 内部使用严格相等比较器(===),它将在这种情况下将每个数组视为唯一。
    我们无法为 JavaScript Set 自定义对象相等性

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

使用 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);
      });
  });

这个问题更多的是一个学习练习,而不是任何应用问题。

javascript arrays filter set unique
6个回答
38
投票

一种方法是将数组转换为 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)


4
投票

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

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
投票

我发现最快的方法是:

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])
  )



2
投票

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);



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


0
投票

const arr = [ [1, 1, 2], [1, 2, 1], [1, 1, 2], [1, 2, 1], [2, 1, 1], [2, 1, 1] ]; const result = arr.reduce((unique, a) => (unique.find(el => el[0] === a[0] && el[1] === a[1] && el[2] === a[2]) ? unique : [...unique, a]), []); console.log(result);

参考资料:

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
© www.soinside.com 2019 - 2024. All rights reserved.