I like this solution better because it abstracts away the collation but allows you to control how items are collated using a higher-order function.
Notice how we don't say anything about x.id or x.name or names.concat([name]) inside collateBy. This procedure has no knowledge of the kind of data you might be collating.
// generic collation procedure
const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
// reusable collateById procedure
const collateById = collateBy (x => x.id)
// custom concatNames procedure
// note use of `{name:[]}` which is the "seed" value for an empty collation
const concatNames = xs=> {
let collation = collateById ((a={name:[]}, b) =>
Object.assign(a, b, { name: [...a.name, b.name] })
) (xs)
return Array.from(collation.values())
}
// sample data
let arr1 = [
{id: 1, name: "lorem"},
{id: 1, name: "ipsum"},
{id: 2, name: "dolor"}
]
console.log(concatNames (arr1))
Higher order functions demonstrate how powerful generic procedures likes collateBy can be. Here's another example using the exact same collateBy procedure but performing a very different collation
const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
const collateEvenOdd = collateBy (x => x % 2 === 0 ? 'even' : 'odd')
const sumEvenOdd = collateEvenOdd ((a=0, b) => a + b)
let data = [2,3,4,5,6,7]
let collation = sumEvenOdd (data)
let even = collation.get('even')
let odd = collation.get('odd')
console.log('even sum', even) // 2 + 4 + 6 === 12
console.log('odd sum', odd) // 3 + 5 + 7 === 15