How do I transform a List of Maps into a Map of Maps in immutable.js?

Suppose I have an immutable.js List like this:

var xs = Immutable.fromJS([{key: "k", text: "foo"}])

I want to transform that into a Map that looks like this:

var ys = Immutable.fromJS({k: {key: "k", text: "foo"}})

How do I turn xs into ys idiomatically in immutable.js?

By idiomatically I mean that any intermediate structures should be immutable.js structures, and I think that any intermediate steps would use iterable composition instead of creating full-size intermediate representations.

Edit: I’ve created a jsperf benchmark comparing the answers provided so far. Both non-mutating solutions feel fairly idiomatic to me; I may hold out and let votes decide the chosen answer or hold out until we can gather a collection of roughly equally idiomatic techniques.

You can reduce the input list into new Immutable.Map:

var ys = xs.reduce(
      function(result, item) { return result.set(item.get('key'), item); }, 
      Immutable.Map());

There is no intermediate representation in this case, but the immutable map has to be updated (in fact, new instance must be created) in every iteration and that that can be suboptimal (depending on the actual implementation of Immutable.Map).

You can optimize it reducing into regular javascript object and convert it to immutable map at the end:

var ys = Immutable.Map(xs.reduce(
      function(result, item) { result[item.get('key')] = item; return result; }, 
      {}));

But that is certainly less idiomatic.

One solution may be to use Map constructor from List:

const ys = Immutable.Map(xs.map(v => [v.get('key'), v]));

Seems like this, but i’m not sure about intermediate representations

ys = Immutable
    .fromJS([{key:'k', value:'xxx'}])
    .toKeyedSeq()
    .mapEntries(function (kv) { return [kv[1].get('key'), kv[1]]; })

PS It’s strange, but i’m can only use .toKeyedSeq, not .toKeyedIterable, which is more appropriate.

Read More:   Remove table row after clicking table row delete button

You can swap a List of Maps to a Map of Lists by using reduce combined with mergeWith.

Reduce through the collection and merge each new item by concatenating its values together.

collection.reduce((rr, ii) => rr.mergeWith((aa, bb) => List().concat(aa, bb), ii))


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts