I found a couple of similar questions, but they were mostly outdated. Here's the problem: create a flat array from the values in several arrays contained in several nested objects.
const data = [
{ id: 1, items: ['one', 'two', 'three'] },
{ id: 2, items: ['two', 'one', 'four'] },
]
Expected result const result = ['one', 'two', 'three', 'four']
My current solution:
function() {
const result = []
data.forEach(item => data.items.forEach(item => result.push(item)))
return _.uniq(result)
}
lodash is allowed
Any suggestion is more than welcome
2 Answers 2
Although at the time of writing, flatMap
is not in every browser (according to MDN not in Edge and Samsung Internet);
data.flatMap(obj => obj.items).filter((e, i, ary) => ary.indexOf(e) == i)
Although, you could check the uniqueness from the result array in your code, and push only if not in there, to save one loop over the array.
Another option would be a reducer like
uniqItems = (acc, {items}) => acc.concat(items.filter(item => acc.indexOf(item) < 0))
to data.reduce(uniqItems, [])
.
Use a Set, it will store unique items for you.
You can convert the set to an array with [...set.values()];
Or as a set is iterateable there is no need to convert it to an array until needed if at all.
const data = [{items: ['one', 'two', 'three'] },{items: ['two', 'one', 'four'] }];
// Quickest solution
function getUniqueA(arr) {
const unique = new Set();
for (const {items} of arr) {
for (const item of items) { unique.add(item) }
}
return [...unique.values()];
}
// Smallest solution
const getUniqueB = arr => [...(new Set(arr.map(i => i.items).flat())).values()];
// Returns the set
const getUniqueC = arr => new Set(arr.map(i => i.items).flat());
const resA = getUniqueA(data);
const resB = getUniqueB(data);
const resC = getUniqueC(data);
logArray("Result A: ", resA);
logArray("Result B: ", resB);
logArray("Result C: ", ...resC);
function logArray(t, ...a) { console.log(t + `[${a}]`) }