我有多个对象数组:
var lists = [];
lists.push([{label: 'a'}, {label: 'b'}, {label: 'c'}]);
lists.push([{label: 'b'}, {label: 'a'}, {label: 'e'}]);
lists.push([{label: 'a'}, {label: 'e'}, {label: 'b'}]);
我想检索所有列表中至少出现一次的所有对象,在这种情况下:{label: 'a'}
和{label: 'b'}
这是我的代码:
var lists = [];
lists.push([{label: 'a'}, {label: 'b'}, {label: 'c'}]);
lists.push([{label: 'b'}, {label: 'a'}, {label: 'e'}]);
lists.push([{label: 'a'}, {label: 'e'}, {label: 'b'}]);
var tmp = [];
for(var i = 0; i < lists.length; i++){
var list = lists[i];
for(var j = 0; j < list.length; j++){
var obj = list[j];
if( !tmp[obj.label] ){
obj.inList = [];
tmp[obj.label] = obj;
}
tmp[obj.label].inList[i] = true;
}
}
var result = [];
for(var key in tmp){
result.push(tmp[key]);
}
var result = result.filter(function(obj){
return Object.keys(obj.inList).length === lists.length;
});
// expected result [{label: 'a'}, {label: 'b'}]
console.log(result);
我的代码可以运行,但是在大型数组下性能较差。有最快的方法吗?
答案 0 :(得分:2)
您可以遍历所有数组一次并创建一个映射。将每个标签映射到一个集合,其中包含该标签所在的所有子数组的索引。如果set
的大小是父数组大小的=
(在您的情况下为lists
),则意味着标签出现在所有子数组中,因为set不会包含重复的条目,并且size等于lists.length
,这意味着标签存在于所有子数组中(可以肯定的是,我们将每个子数组的索引添加到集合中)。请尝试以下操作:
var lists = [];
lists.push([{label: 'a'}, {label: 'b'}, {label: 'c'}]);
lists.push([{label: 'b'}, {label: 'a'}, {label: 'e'}]);
lists.push([{label: 'a'}, {label: 'e'}, {label: 'b'}]);
let map = {};
lists.forEach((list, index)=>{
list.forEach((label)=>{
map[label.label] = map[label.label] || new Set();
map[label.label].add(index);
});
});
let result = [];
Object.keys(map).forEach((key)=>{
if(map[key].size == lists.length)
result.push({label : key});
});
console.log(result);
答案 1 :(得分:2)
一种方法是遍历每个列表,并在每次看到对象时为每个标签增加一个计数器。然后,一旦处理完所有列表,所有计数等于列表数量的标签都必须出现在所有列表中。
例如:
function OmnipresentObjectTracker(key) {
var arrayCount = 0
var presentCounts = {}
var objectsByKeyname = {}
this.add = function(arr) {
arrayCount++
var alreadyCounted = {}
arr.forEach(function(obj) {
if (key in obj) {
const value = obj[key]
objectsByKeyname[value] = obj
if (!alreadyCounted[value]) {
presentCounts[value] = (presentCounts[value]||0) + 1
alreadyCounted[value] = true;
}
}
})
}
this.getObjects = function() {
return Object.keys(presentCounts).reduce(function(memo, k) {
if (presentCounts[k] === arrayCount) {
memo.push(objectsByKeyname[k])
}
return memo
}, [])
}
}
var oot = new OmnipresentObjectTracker('label')
oot.add([{label: 'a'}, {label: 'b'}, {label: 'c'}]);
oot.getObjects() // => [{label: "a"}, {label: "b"}, {label: "c"}]
oot.add([{label: 'b'}, {label: 'a'}, {label: 'e'}]);
oot.add([{label: 'a'}, {label: 'e'}, {label: 'b'}]);
oot.getObjects() // => [{label: "a"}, {label: "b"}]
oot.add([{label: 'a'}, {label: 'a'}])
oot.getObjects() // => [{label: "a"}]
答案 2 :(得分:1)
您可以使用array#reduce
将所有唯一键及其计数添加到对象累加器中。然后使用array#filter
筛选出所有等于您的数组长度的键,然后重新生成对象数组。
var lists = [];
lists.push([{label: 'a'}, {label: 'b'}, {label: 'c'}]);
lists.push([{label: 'b'}, {label: 'a'}, {label: 'e'}]);
lists.push([{label: 'a'}, {label: 'e'}, {label: 'b'}]);
var common = lists.reduce((r, a) => {
var unique = [...new Set(a.map(({label}) => label))];
unique.forEach(v => {
v in r ? r[v]++: r[v] = 1;
});
return r;
},{});
var result = Object.keys(common).filter(k => common[k] === lists.length).map(label => ({label}));
console.log(result);
答案 3 :(得分:0)
我要稍微修改一下并丢弃每个数组中未找到的元素。这样,每个数组的迭代次数都会减少。像这样:
var lists = [];
lists.push([{label: 'a'}, {label: 'b'}, {label: 'c'}]);
lists.push([{label: 'b'}, {label: 'a'}, {label: 'e'}]);
lists.push([{label: 'a'}, {label: 'e'}, {label: 'b'}]);
var final = [];
// Add every element from the first list
for(var e in lists[0]) {
final.push(lists[0][e]);
}
// Iterate every list item in the main array
for(var list in lists) {
// Iterate only the remaining elements in the final array
for(var f in final) {
var exists = false; // Sentinel that checks if the element exists
for(var e in lists[list]) {
if(final[f].label == lists[list][e].label) {
exists = true; // Change the flag if the element is found
}
}
// If the element was not found, remove the element from the final array
if(!exists) {
final.splice(f,1);
}
}
}
console.log(final);
/*
[
{
"label": "a"
},
{
"label": "b"
}
]
*/