问题
I have an array of arrays of objects which looks like this:
let fruitSamples = [
[
{'id': 1,'type': 'apples','samples': [1, 2, 3]},
{'id': 2,'type': 'bananas','samples': [1, 2, 7]},
{'id': 3,'type': 'pears','samples': [1, 2, 3]}
],
[
{'id': 1,'type': 'apples','samples': [5, 2, 9]},
{'id': 2,'type': 'bananas','samples': [1, 7, 7]},
{'id': 3,'type': 'pears','samples': [12, 21, 32]}
],
[
{'id': 1,'type': 'apples','samples': [11, 2, 33]},
{'id': 2,'type': 'bananas','samples': [17, 2, 67]},
{'id': 3,'type': 'pears','samples': [91, 22, 34]}
]
];
I want to reduce and merge the above array using lodash into one so that the samples get concatenated together like so:
fruitSamples = [
{'id': 1, 'type': 'apples', 'samples': [1,2,3,5,2,9,11,2,33]},
{'id': 2, 'type': 'bananas', 'samples': [1,2,7,1,7,7,17,2,67]},
{'id': 3, 'type': 'pears', 'samples': [1,2,3,12,21,32,91,22,34]},
]
I have tried many different approaches but since I want the shortest possible way of solving this what would be your recommendations?
I have tried this:
let test = _(fruitSamples)
.flatten()
.groupBy('type')
.map(_.spread(_.merge))
.value();
console.log(test);
This gives me the following result, which does not concatenate the samples:
test = [
{'id': 1,'type': 'apples','samples': [11, 2, 33]},
{'id': 2,'type': 'bananas','samples': [17, 2, 67]},
{'id': 3,'type': 'pears','samples': [91, 22, 34]}
]
I feel using _.mergeWith might be the right answer, if so, I am looking for help implementing mergeWith in the best possible way as I am not sure how to do it. Any suggestions?
回答1:
Instead of _.merge
, you could try using _.mergeWith that accepts a customizer
function which you can use to customize the assigned values.
From the official docs:
This method is like
_.merge
except that it accepts customizer which is invoked to produce the merged values of the destination and source properties.
let fruitSamples = [
[
{'id': 1,'type': 'apples','samples': [1, 2, 3]},
{'id': 2,'type': 'bananas','samples': [1, 2, 7]},
{'id': 3,'type': 'pears','samples': [1, 2, 3]}
],
[
{'id': 1,'type': 'apples','samples': [5, 2, 9]},
{'id': 2,'type': 'bananas','samples': [1, 7, 7]},
{'id': 3,'type': 'pears','samples': [12, 21, 32]}
],
[
{'id': 1,'type': 'apples','samples': [11, 2, 33]},
{'id': 2,'type': 'bananas','samples': [17, 2, 67]},
{'id': 3,'type': 'pears','samples': [91, 22, 34]}
]
];
function customizer(objValue, srcValue) {
if (_.isArray(objValue)) {
return objValue.concat(srcValue);
}
}
let test = _(fruitSamples)
.flatten()
.groupBy('type')
.map(_.spread((...values) => {
return _.mergeWith(...values, customizer);
}))
.value();
console.log(test);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
回答2:
Not sure how to do using lodash, but pure Javascript it's not too difficult.
Update: Thanks to @Taki doing a
flat()
first makes this even easier..
let fruitSamples = [[{"id":1,"type":"apples","samples":[1,2,3]},{"id":2,"type":"bananas","samples":[1,2,7]},{"id":3,"type":"pears","samples":[1,2,3]}],[{"id":1,"type":"apples","samples":[5,2,9]},{"id":2,"type":"bananas","samples":[1,7,7]},{"id":3,"type":"pears","samples":[12,21,32]}],[{"id":1,"type":"apples","samples":[11,2,33]},{"id":2,"type":"bananas","samples":[17,2,67]},{"id":3,"type":"pears","samples":[91,22,34]}]];
let concat = fruitSamples.flat().reduce((a, i) => {
const f = a.find(f => f.id === i.id);
if (!f) a.push(i);
else f.samples = [...f.samples, ...i.samples];
return a;
}, []);
console.log(concat);
回答3:
You can first convert the array or arrays to simple array using .reduce
and then group by using .reduce again.
May be more easy to grab
Something like
let fruitSamples = [
[
{'id': 1,'type': 'apples','samples': [1, 2, 3]},
{'id': 2,'type': 'bananas','samples': [1, 2, 7]},
{'id': 3,'type': 'pears','samples': [1, 2, 3]}
],
[
{'id': 1,'type': 'apples','samples': [5, 2, 9]},
{'id': 2,'type': 'bananas','samples': [1, 7, 7]},
{'id': 3,'type': 'pears','samples': [12, 21, 32]}
],
[
{'id': 1,'type': 'apples','samples': [11, 2, 33]},
{'id': 2,'type': 'bananas','samples': [17, 2, 67]},
{'id': 3,'type': 'pears','samples': [91, 22, 34]}
]
];
var merged = fruitSamples.reduce(function(prev, next) {
return prev.concat(next);
});
var res = merged.reduce(function(prev, next) {
var index = prev.findIndex(o=> o.id == next.id)
if(index >= 0)
prev[index].samples = [...prev[index].samples,...next.samples];
else
prev.push(next);
return prev;
},[]);
console.log(res)
回答4:
One way to do it with javascript and no lodash:
var fruitSamples = [
[
{'id': 1,'type': 'apples','samples': [1, 2, 3]},
{'id': 2,'type': 'bananas','samples': [1, 2, 7]},
{'id': 3,'type': 'pears','samples': [1, 2, 3]}
],
[
{'id': 1,'type': 'apples','samples': [5, 2, 9]},
{'id': 2,'type': 'bananas','samples': [1, 7, 7]},
{'id': 3,'type': 'pears','samples': [12, 21, 32]}
],
[
{'id': 1,'type': 'apples','samples': [11, 2, 33]},
{'id': 2,'type': 'bananas','samples': [17, 2, 67]},
{'id': 3,'type': 'pears','samples': [91, 22, 34]}
]
];
var test = fruitSamples.flat().reduce((rv,x)=>{
var f = rv.find(y => y.id == x.id);
if(f == null){
f ={"id":x.id, "type":x.type,"samples":x.samples};
rv.push(f);
}
else{
f.samples = f.samples.concat(x.samples);
}
return rv;
},[]);
console.log(JSON.stringify(test))
https://jsfiddle.net/pimboden40/y8x96sbg/1/
来源:https://stackoverflow.com/questions/54025657/how-to-merge-concatenate-values-of-same-object-properties-in-an-array-of-objects