[HN Gopher] Using GroupBy on an array of objects in JavaScript
___________________________________________________________________
Using GroupBy on an array of objects in JavaScript
Author : saranshk
Score : 68 points
Date : 2021-12-29 15:39 UTC (7 hours ago)
(HTM) web link (www.wisdomgeek.com)
(TXT) w3m dump (www.wisdomgeek.com)
| jbverschoor wrote:
| Oh lord... so you group by a Number, but the map-key becomes a
| String. Sounds like idiomatic JavaScript
| saranshk wrote:
| groupByToMap would be useful in that case as pointed out in
| another comment. Updated the post with that.
| ojr wrote:
| Javascript has been so widely used for so long, there are two
| types of languages one that people hate and one that people
| don't use
| [deleted]
| throw_m239339 wrote:
| This isn't a map, Javascript has a dedicated map type. In
| JavaScript, Objects keys can only be strings or symbols.
| mberning wrote:
| I worked on a Ruby gem to add group_by and aggregate_by functions
| to collections/enumerables. I finished about 1/2 of the
| functionality and found the implementation to be hateful and
| thought it would be received poorly. Now seeing this I am second
| guessing myself.
| caseyohara wrote:
| Enumerable#group_by is in Ruby core https://ruby-
| doc.org/core-3.0.2/Enumerable.html#method-i-gro...
| gfunk911 wrote:
| Ruby already has group_by, unless I'm misunderstanding what
| you're saying
| mahesh_rm wrote:
| Where was this when I needed it? Happy discovery.
| saranshk wrote:
| probably would not have been written then, it is a stage 3
| proposal but should be merged in hopefully soon.
| zackmorris wrote:
| For what it's worth, the Laravel PHP framework (no affiliation)
| has the best introduction to higher-order methods for imperative
| programmers used to Javascript/C style of anything that I've come
| across:
|
| 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.
| newlisp wrote:
| I normally just write 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)) }
| saranshk wrote:
| while there is nothing wrong with that, it's always good to
| have these things built-in as native functions instead.
| [deleted]
| duxup wrote:
| I was just doing something like this and thinking "I do this in
| SQL all the time but users like to change things up so much it
| should be a native array thing."
| saranshk wrote:
| all of lodash features would probably become a native thing
| soon enough
| yashap wrote:
| Personally I'd have this return a map instead of an object, so
| that the keys aren't forced to be strings. Otherwise seems like a
| reasonable API, very similar to groupBy in any other moderately
| functional language, except with the "keys must be strings"
| restriction inherited from returning a plain object.
|
| 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.
| shawnz wrote:
| It looks like they are also creating a "groupByToMap" for that
| reason. See: https://github.com/tc39/proposal-array-grouping
|
| 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/
| yashap wrote:
| Ah fair enough!
| saranshk wrote:
| updated the post with groupByToMap, Thanks for pointing that
| out.
| roebk wrote:
| I wonder if groupBy should have had some sort of into
| argument. Otherwise, we may end up with four groupBy methods.
| groupBy, groupByToMap, groupByToWeakMap and groupByToRecord
| (should records land).
|
| Edit: this has already been discussed
| https://github.com/tc39/proposal-array-grouping/issues/3
| masklinn wrote:
| > Otherwise seems like a reasonable API, very similar to
| groupBy in any other moderately functional language
|
| Though lots of them implement the less useful but stream-able
| groupBy which only groups siblings matching the predicate (or
| key function).
| jraph wrote:
| I found this article a bit verbose (maybe because I'm already
| familiar with the topic) and yet missing three "key" (ah ah)
| points:
|
| - 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...
|
| [2] https://tc39.es/ecma262/#sec-object-type
| wereHamster wrote:
| A <<group by>> function requires keys to be comparable (for
| equality). You can see this when you look at the type
| signatures of <<group by>> functions in any strongly typed
| language or library. They either require a comparator to be
| provided, or infer it from the context (type classes in
| Haskell). JavaScript has quite intuitive equality for primitive
| types (strings, symbols), but nothing that would be natural for
| complex objects.
|
| 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.
| beebeepka wrote:
| Key strings can also contain emojis. Not that I would recommend
| it in most situations
| VWWHFSfQ wrote:
| it's just utf8 bytes right
| badjeans wrote:
| Hardly shorter than just writing the for loop, i.e. the example
| in python groupByAge =
| collections.defaultdict(list) for person in people:
| groupByAge[person["age"]].append(person)
| shhsshs wrote:
| In JS you would also need to check if the key exists first (so
| you can add it). I think the minimal example would be:
| 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)
| SahAssar wrote:
| A reduce version seems quite okay to me though, and keeps it
| pretty functional-styled. const groupByAge
| = people.reduce((previous, current) => { if
| (!previous[current.age]) previous[current.age] = []
| previous[current.age].push(current) return previous
| }, {})
| ksbrooksjr wrote:
| Unfortunately the typescript definitions for these two methods
| haven't been written yet [1].
|
| [1] https://github.com/microsoft/TypeScript/issues/47171
___________________________________________________________________
(page generated 2021-12-29 23:01 UTC)