After having spent a few hours trying to solve This Question, I decided to take a look the solution and I can’t seem to get a part of the solution through my thick skull.
Solution:
const myGroupBy = (collection, q) => { collection = Object.values(collection); switch (typeof q) { case "string": return collection.reduce((a, c) => (a[c[q]] = [...(a[c[q]] || []), c], a), {}); case "function": return collection.reduce((a, c) => (a[q(c)] = [...(a[q(c)] || []), c], a), {}); default: const [[k, v]] = Object.entries(q); return collection.reduce((a, c) => (a[c[k] === v] = [...(a[c[k] === v] || []), c], a), {}); } };
The part I don’t understand: (a[c[q]] = [...(a[c[q]] || []), c], a)
Any help would be greatly appreciated.
Answer
It’s a difficult-to-understand way of adding a new item to an array when the array might not exist yet.
.reduce((a, c) => (a[c[q]] = [...(a[c[q]] || []), c], a), {});
is, unminified:
.reduce((a, c) => { const prop = c[q]; if (!a[prop]) { // array doesn't exist yet; create it a[prop] = []; } // it definitely exists now. Now, push the new item to it a[prop].push(c); // return the accumulator return a; }, {});
The same pattern is being used for the other .reduce
s here.
.reduce
arguably isn’t very appropriate here though, a plain loop would make more sense since the accumulator never changes.
const obj = {}; for (const c of collection) { const prop = c[q]; if (!obj[prop]) { // array doesn't exist yet; create it obj[prop] = []; } // it definitely exists now. Now, push the new item to it obj[prop].push(c); } return obj;
These approaches do mutate the existing arrays on the accumulator instead of reassigning entirely new arrays (like your original code does) – but since the array starts out empty, it won’t have any effect (positive or negative).