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.
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))