Using GroupBy on an array of objects in JavaScript
wisdomgeek.com
wisdomgeek.com
Also, for those thinking JS objects can have non-string keys, they can’t, it just sometimes appears that way due to JS type coercion: https://www.becomebetterprogrammer.com/can-javasscript-objec...
Edit: as pointed out by shawnz, this isn’t entirely accurate, JS object keys can also be symbols.
Property keys can also be symbol objects and it seems like that's supported by the groupBy function in addition to strings, see: https://tc39.es/proposal-array-grouping/
Edit: this has already been discussed https://github.com/tc39/proposal-array-grouping/issues/3
- one can get the keys of an object by using Object.keys or a for-in loop and notice that keys are always strings, even when using arrays.
- the object definition syntax [1] is set to define property strings by the standard (and symbols). You can (and probably should) experiment, but the spec will tell you what happens anyway with 100% certainty (except for implementation bugs, but that's not what we are looking for).
- the definitive answer to "what kind of value an object key can be in Javascript?" is given by the section "The Object Type" of the ECMAScript standard [2]:
> Properties are identified using key values. A property key value is either an ECMAScript String value or a Symbol value. All String and Symbol values, including the empty String, are valid as property keys. A property name is a property key that is a String value.
Experimentation helps anchoring things in memory and building intuition, as well as getting into things. Inviting people to experiment by themselves and not blindly trust what they read is a fantastic advice. I do experiment a lot myself. However, experimentation is not the best way to "prove" things (contrary to what the article states). Definitive answers should be found in specifications and documentations (or implementation sources). No amount of experimentation will be enough to convince me of "See? I did this this and this, and it's always strings".
The article is well written, the same thing with these references to the spec would make it strong and irrefutable.
[1] https://tc39.es/ecma262/#sec-object-initializer-static-seman...
Consider this array: [{ key: {}, foo: 1 }, { key: {}, foo: 2 }], there are multiple answers how a Map can look when you group by 'key'. Both comparing the keys using '===' and deep equality are valid options, depending on needs.
It sounds like they're going to implement `groupByToMap` as well as `groupBy`, and I assume `groupByToMap` will just use the normal map key equality rules, and I guess the "first" key matching that equality will be used for the grouping.
See for example https://gcanti.github.io/fp-ts/modules/NonEmptyArray.ts.html..., where you can supply your own equality function…
Though lots of them implement the less useful but stream-able groupBy which only groups siblings matching the predicate (or key function).
Though I do often see people using a combination of maps, filters, reduces, lodash functions etc. one by one, rather than doing everything in a single for in loop. In most cases it feels that For In is still the most performant option, as you want to manipulate the data in more ways than just grouping
https://laravel.com/docs/master/collections
Most of these methods are also available as part of the Eloquent ORM, for filtering/reshaping queries before they're executed:
https://laravel.com/docs/master/eloquent
Since being exposed to this way of working, I rarely use foreach() anymore, much less for(). The main downside being that I find most other languages tedious to work in now. LINQ in .NET/C# is nice, there might be others.
groupByAge = collections.defaultdict(list)
for person in people:
groupByAge[person["age"]].append(person) const groupByAge = {}
for (const person in people) {
if (!groupByAge[person.age]) {
groupByAge[person.age] = []
}
groupByAge[person.age].push(person)
}
IMO it is a very nice change to now be able to write: const groupByAge = people.groupBy(p => p.age) const groupByAge = people.reduce((previous, current) => {
if (!previous[current.age]) previous[current.age] = []
previous[current.age].push(current)
return previous
}, {}) const groupBy = (fn, arr) => {
return arr.reduce((o, e) => {
const k = fn(e)
if (o[k] !== undefined) o[k].push(e)
else o[k] = [e]
return o
} Object.create(null))
}