如何在immutable.js中将一个Map列表转换为Map的Map?

23

假设我有一个 immutable.js 的 List,像这样:

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

我希望将它转换为这样的一个Map:

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

如何在immutable.js中使用惯用语将xs转换为ys

通过“惯用语”,我的意思是任何中间结构都应该是immutable.js结构,而我认为任何中间步骤都应该使用迭代组合而不是创建完整的中间表示。

编辑:我创建了一个jsperf基准测试来比较到目前为止提供的答案。对我来说,两个非变异解决方案都相当惯用;我可能会坚持并让投票决定选择的答案,或者坚持直到我们能够收集到大约同样惯用的技术集合。


你真的想要一个Map of Maps,还是想要一个对象的Map? - Bergi
1
@Bergi Map of Maps - 从上到下都是不可变的。 - CJ Gaconnet
4个回答

24

一种解决方案是使用List构造函数中的Map:

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

23

你可以将输入的列表缩减为一个新的Immutable.Map:

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

在这种情况下没有中间表示,但是不可变的Map必须在每次迭代中更新(实际上必须创建新的实例),这可能不是最优的(取决于Immutable.Map的实际实现)。

您可以将其优化为将其缩小为常规JavaScript对象,并在最后将其转换为不可变的Map:

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

但那显然不太地道。


感谢您理性的回答!我认为这是最好的答案。但是,当我比较每次迭代更新地图与在末尾构建新地图的性能时,我始终看到第一种方法几乎比后者快10%,这与您在结尾提到的相反:https://jsperf.com/immutable-js-list-of-maps-to-map-of-maps/1 - theopak

2

看起来是这样,但我对中间表示不确定。

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

PS 这很奇怪,但我只能使用 .toKeyedSeq,而不能使用更合适的 .toKeyedIterable。


0
你可以使用 reduce 结合 mergeWith 将 Map 列表交换为列表的 Map。
通过遍历整个集合并将每个新项目合并在一起,通过连接它们的值来实现。
collection.reduce((rr, ii) => rr.mergeWith((aa, bb) => List().concat(aa, bb), ii))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接