91

I need to generate a couple of objects from lists in Javascript. In Python, I'd write this:

{key_maker(x): val_maker(x) for x in a_list}

Another way to ask is does there exist something like jQuery.map() which aggregates objects? Here's my guess (doesn't work):

var result = {}
$.map(a_list, function(x) {
    $.extend(result, {key_maker(x): val_maker(x)})
})
Cuadue
  • 3,769
  • 3
  • 24
  • 38
  • 1
    FYI, your `$.extend` version won't work. Property identifiers in object literal notation can't be the result of an expression. This code will fail... `{key_maker(x): val_maker(x)}` –  Jun 17 '12 at 01:39

7 Answers7

73

Here's a version that doesn't use reduce:

Object.fromEntries( a_list.map( x => [key_maker(x), value_maker(x)]) );

Object.fromEntries is basically the same as _.fromPairs in Lodash. This feels the most like the Python dict comprehension to me.

fizzyh2o
  • 1,237
  • 9
  • 18
  • 2
    It's the closer we can get to the comprehension without special syntax IMO, though as of Jan 2019 it's still a proposal and not implemented in NodeJS. – villasv Jan 04 '19 at 13:00
  • I think this is quite dict comprehension-like, and could probably be the accepted answer – memo Dec 26 '20 at 19:07
61

Assuming a_list is an Array, the closest would probably be to use .reduce().

var result = a_list.reduce(function(obj, x) {
    obj[key_maker(x)] = val_maker(x);
    return obj;
}, {});

Array comprehensions are likely coming in a future version of JavaScript.


You can patch non ES5 compliant implementations with the compatibility patch from MDN.


If a_list is not an Array, but a plain object, you can use Object.keys() to perform the same operation.

var result = Object.keys(a_list).reduce(function(obj, x) {
    obj[key_maker(a_list[x])] = val_maker(a_list[x]);
    return obj;
}, {});
Michael
  • 8,362
  • 6
  • 61
  • 88
  • If using a version of JS that doesn't have `reduce`, I don't think jQuery ever added it, either. But underscore has it. – Mark Reed Jun 17 '12 at 01:31
  • @MarkReed: True. I updated with a link to the MDN compatibility patch. –  Jun 17 '12 at 01:34
  • jQuery does not have reduce (yet). You can find some implementations in its trac here: http://bugs.jquery.com/ticket/1886 – Jeroen K Jan 09 '14 at 11:37
  • 3
    Using underscore or lodash, it would be: `_.reduce(a_list, function(obj, x){ ... }, {});` – metakermit Jan 29 '15 at 15:17
  • A slightly shorter version using arrow notation and the comma operator: `a_list.reduce((o, x) => (o[key_maker(x)] = val_maker(x), o), {})` – Avner Dec 21 '19 at 23:40
8

Old question, but the answer has changed slightly in new versions of Javascript. With ES2015 (ES6) you can achieve a one-liner object comprehension like this:

a_list.reduce((obj, x) => Object.assign(obj, { [key_maker(x)]: value_maker(x) }), {})
benwixen
  • 972
  • 9
  • 15
6

ES5 introduced Map for an OrderedDict. A Map comprehension might look like:

Map( Array.map(function(o){return[ key_maker(o), val_maker(o) ]}))

Example:

> a_list = [ {x:1}, {x:2}, {x:3} ]
< [ Object, Object, Object ]
>
> let dict = new Map(a_list.map(function(o){return[ o.x, o.x**2 ]}))
< Map[3]
< 0 : {1 => 1}
< 1 : {2 => 4}
< 2 : {3 => 9}
>
> dict.get(2)
< 4
Steven Almeroth
  • 7,758
  • 2
  • 50
  • 57
6

Maybe something like this, using Lodash: var result = _.fromPairs(a_list.map(x => [key_maker(x), value_maker(x)]));

Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
4

A shorter ES6 version would be:

a_list.reduce((obj, x) => (obj[key_maker(x)] = val_maker(x), obj),{})
SnowOnion
  • 329
  • 2
  • 11
smartexpert
  • 2,625
  • 3
  • 24
  • 41
1

I'm using the latest version of typescript and I use

const list = [1, 2, 3, ...];
const obj = Object.fromEntries(array.map(val, idx) => [func1(val), func2(val)]))
// python equivalent: {func1(x): func2(x) for x in a_list}
Ivan Gonzalez
  • 446
  • 1
  • 5
  • 14