Reputation: 2588
I have this problem which I have tried to solve to no avail.
In this array of arrays, when two or more color keys in the objects match with any other set of array's objects color keys, I would like to add a boolean key called match
to each of those array's objects, regardless of whether every key matches.
For example, two objects in the data[0][0]
and data[0][1]
arrays share the key color
white
and black
, so that is a match: true
for all objects in data[0][0]
and data[0][1]
but not data[0][2]
as this only has one, therefore it will be match: false
.
The result would look like this:
data = [
[{
name: 'car',
color: 'black',
group: 0,
match: true
},{
name: 'car',
color: 'white',
group: 0,
match: true
},{
name: 'car',
color: 'blue',
group: 0,
match: true
}],
[{
name: 'truck',
color: 'black'
group: 1,
match: true
},{
name: 'truck',
color: 'white',
group: 1,
match: true
},{
name: 'truck',
color: 'yellow',
group: 1,
match: true
}],
[{
name: 'moto',
color: 'black',
group: 2,
match: false
},{
name: 'moto',
color: 'pink',
group: 2,
match: false
},{
name: 'moto',
color: 'orange',
group: 2,
match: false
}]
]
This is a small sample. The actual data has hundreds of arrays and the match should be a minimum of 7
Upvotes: 0
Views: 64
Reputation: 51886
You can calculate an intersection of colors
as an array and compare the length
to your expected threshold to determine the value of match
in your results.
function match (data, key, filter, transform) {
const arrays = data.map(
array => array.map(key)
);
const groups = arrays.map(
array => ({ array, set: new Set(array) })
);
const matches = groups.map(
outer => groups.some(
inner => (
outer !== inner &&
filter(outer.array.filter(inner.set.has, inner.set))
)
)
);
return data.map(
(array, index) => transform(array, matches[index])
);
}
const data = [[{name:'car',color:'black',group:0},{name:'car',color:'white',group:0},{name:'car',color:'blue',group:0}],[{name:'truck',color:'black',group:1},{name:'truck',color:'white',group:1},{name:'truck',color:'yellow',group:1}],[{name:'moto',color:'black',group:2},{name:'moto',color:'pink',group:2},{name:'moto',color:'orange',group:2}]];
const result = match(
data,
value => value.color,
keys => keys.length >= 2,
(array, match) => array.map(
value => Object.assign(value, { match })
)
);
console.log(result);
This creates a Set()
for each array of colors
to more efficiently calculate the intersection at each pass without skipping duplicates, if there are any.
For your actual data, you can change the filter
parameter to
colors => colors.length >= 7
Upvotes: 1
Reputation: 386654
You could count black and white and get new objects with match
.
var data = [[{ name: 'car', color: 'black', group: 0 }, { name: 'car', color: 'white', group: 0 }, { name: 'car', color: 'blue', group: 0 }], [{ name: 'truck', color: 'black', group: 1 }, { name: 'truck', color: 'white', group: 1 }, { name: 'truck', color: 'yellow', group: 1 }], [{ name: 'moto', color: 'black', group: 2 }, { name: 'moto', color: 'pink', group: 2 }, { name: 'moto', color: 'orange', group: 2 }]],
result = data.map(a => {
var count = {},
match = a.some(({ color }) => {
count[color] = (count[color] || 0) + 1;
return count.black === 1 && count.white === 1;
});
return a.map(o => Object.assign({}, o, { match }));
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0