我正在尝试构建唯一的数组数组,这样每当我有新数组要添加时,它只应在集合中尚不存在时才添加
例如存储 [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]]
我尝试过的方法:
uniqueArrComparer
中的每个值都是对该数组元素的唯一对象引用。function uniqueArrComparer(value, index, self) {
return self.indexOf(value) === index;
}
result.filter(uniqueArrComparer)
Set/Map:以为我可以构建一个唯一的数组集,但它不起作用,因为 Set 内部使用严格相等比较器(===),它将在这种情况下将每个数组视为唯一。
我们无法为 JavaScript Set 自定义对象相等性
将每个数组元素作为字符串存储在 Set/Map/Array 中,并构建一个唯一字符串数组。最后使用唯一字符串数组构建数组数组。这种方法会起作用,但看起来不像有效的解决方案。
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);
});
});
这个问题更多的是一个学习练习,而不是任何应用问题。
一种方法是将数组转换为 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)
如果您可以使用库,请尝试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}]
我发现最快的方法是:
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])
)
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);
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
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);
参考资料: