Proposal: Object.associateBy and Map.associateBy. A singular counterpart to groupBy.

Hey everyone!

ES2024 provided Object.groupBy and Map.groupBy static methods, and I think associateBy may be a natural complement for them.

Right now, when I need a lookup table, I end up writing smth like this (or extracting it to helper function):

const idToUser = Object.fromEntries(users.map(u => [u.id, u]));

which is fine but kinda annoying - two passes, intermediate tuples, doesn't work with iterables.

So the idea: Object.associateBy and Map.associateBy.

const idToUser = Object.associateBy(users, u => u.id);
const idToUserMap = Map.associateBy(users, u => u.id);

Single pass, any iterable, same API shape as groupBy. Duplicate keys === last wins (consistent with Object.fromEntries / Map constructor).

Basically what Lodash _.keyBy and Kotlin associateBy do. Feels like a natural companion to groupBy.

Repo: GitHub - artem1458/proposal-associate-by ยท GitHub

Really keen to hear your thoughts, thanks!

I wonder if there should be an option to distinguish between last-write-wins and error on duplicate key.

Data validation (like key uniqueness) may be a separate operation provided by user.
It can be validated even inside key selector callback, but in this case it's better to provide access to the object or map which are filling during associateBy process. Maybe as thisArg (but arrow functions won't work with thisArg) or as a separate argument. Otherwise user needs to create other data structure to store added keys.

const addedKeys = new Set();

Map.associateBy(users, user => {
  const key = user.id;

  if (addedKeys.has(user.id)) {
    throw Error('Duplicate key found');
  }

  addedKeys.add(key);

  return key;
});

Hi,

fine but kinda annoying - two passes, intermediate tuples, doesn't work with iterables.

What makes you say that? fromEntries works just fine with iterables,
and iterators also have a .map() method.

You're right, with new .map method for iterables it is working, but you still need to create intermediate tuples, and it's still slower even than polyfill for associateBy (slower by ~68% on jsbench)