在 Javascript 中根据不重复的交集累积合并数组
Cumulatively merge arrays based on intersection without duplicates in Javascript
我有像这样聚集的数据
[[1, 2, 3], [0, 2], [2, 4], [6, 7]]
.
我想合并共享项目而不重复的数组。
例如,我从上述数据中寻找的结果是
[[1, 2, 3, 0, 4], [6, 7]]
.
我的做法是循环遍历数组,当找到交集时,将两个数组形成并集。这是我尝试过的:
let clusters = [[1, 2, 3], [0, 2], [2, 4], [6, 7]];
let len = clusters.length;
let i, j;
for (i = 0; i < len; i++) {
for (j = i+1; j < len; j++) {
if (clusters[i].filter(x => clusters[j].includes(x))) {
clusters[i] = [...new Set([...this.clusters[i], ...this.clusters[j]])]; // this won't work
}
}
}
结果是clusters数组没有变化。我认为如果我能找到一种递归地 运行 联合操作的方法(当满足交集条件时),这可能会起作用。
或者也许有更好的方法?
这可能(我没有真正测试过,以此作为开始研究的想法)可行。
您实际上不需要递归,因为您只处理一个嵌套级别。如果你有一个大数据集,请注意这个不好的性能。
var a=[[1, 2, 3], [0, 2], [2, 4], [6, 7]];
function match(a,b) {
//if you meant _at least_ one match between two elements
for(var i=0;i<a.length;i++) if(b.indexOf(a[i])>0) return true;
return false;
}
function combine(a,b) {
var c=[];
for(var i=0;i<a.length;i++) if(c.indexOf(a[i])<0) c.push(a[i]);
for(var i=0;i<b.length;i++) if(c.indexOf(b[i])<0) c.push(b[i]);
return c;
}
while(1) {
var found=false;
for(var i=0;i<a.length;i++) {
for(var j=0;j<a.length;j++) {
if(i==j) continue;
//if a match is found, merge the two elements and start over
if(match(a[i],a[j])) {
a[i]=combine(a[i],a[j]);
a.splice(j,1);
found=true;
break;
}
}
if(found) break;
}
//repeat until no matches were found
if(!found) break;
}
console.log(a);
您可以使用 Array.reduce
执行此操作,将数组从 clusters
推送到输出数组中的集合中,或者如果值已存在于输出中的集合之一中则合并,然后再转换回来完成后从集合到数组:
let clusters = [
[1, 2, 3],
[0, 2],
[2, 4],
[6, 7]
];
let result = clusters.reduce((c, a) => {
for (i = 0; i < c.length; i++) {
if (a.some(v => c[i].has(v))) {
a.forEach(v => c[i].add(v));
return c;
}
}
c.push(new Set(a));
return c;
}, [])
.map(s => Array.from(s));
console.log(result);
我有像这样聚集的数据
[[1, 2, 3], [0, 2], [2, 4], [6, 7]]
.
我想合并共享项目而不重复的数组。
例如,我从上述数据中寻找的结果是
[[1, 2, 3, 0, 4], [6, 7]]
.
我的做法是循环遍历数组,当找到交集时,将两个数组形成并集。这是我尝试过的:
let clusters = [[1, 2, 3], [0, 2], [2, 4], [6, 7]];
let len = clusters.length;
let i, j;
for (i = 0; i < len; i++) {
for (j = i+1; j < len; j++) {
if (clusters[i].filter(x => clusters[j].includes(x))) {
clusters[i] = [...new Set([...this.clusters[i], ...this.clusters[j]])]; // this won't work
}
}
}
结果是clusters数组没有变化。我认为如果我能找到一种递归地 运行 联合操作的方法(当满足交集条件时),这可能会起作用。
或者也许有更好的方法?
这可能(我没有真正测试过,以此作为开始研究的想法)可行。
您实际上不需要递归,因为您只处理一个嵌套级别。如果你有一个大数据集,请注意这个不好的性能。
var a=[[1, 2, 3], [0, 2], [2, 4], [6, 7]];
function match(a,b) {
//if you meant _at least_ one match between two elements
for(var i=0;i<a.length;i++) if(b.indexOf(a[i])>0) return true;
return false;
}
function combine(a,b) {
var c=[];
for(var i=0;i<a.length;i++) if(c.indexOf(a[i])<0) c.push(a[i]);
for(var i=0;i<b.length;i++) if(c.indexOf(b[i])<0) c.push(b[i]);
return c;
}
while(1) {
var found=false;
for(var i=0;i<a.length;i++) {
for(var j=0;j<a.length;j++) {
if(i==j) continue;
//if a match is found, merge the two elements and start over
if(match(a[i],a[j])) {
a[i]=combine(a[i],a[j]);
a.splice(j,1);
found=true;
break;
}
}
if(found) break;
}
//repeat until no matches were found
if(!found) break;
}
console.log(a);
您可以使用 Array.reduce
执行此操作,将数组从 clusters
推送到输出数组中的集合中,或者如果值已存在于输出中的集合之一中则合并,然后再转换回来完成后从集合到数组:
let clusters = [
[1, 2, 3],
[0, 2],
[2, 4],
[6, 7]
];
let result = clusters.reduce((c, a) => {
for (i = 0; i < c.length; i++) {
if (a.some(v => c[i].has(v))) {
a.forEach(v => c[i].add(v));
return c;
}
}
c.push(new Set(a));
return c;
}, [])
.map(s => Array.from(s));
console.log(result);