次のようなimmutable.js List
があるとします。
var xs = Immutable.fromJS([{key: "k", text: "foo"}])
それを次のようなマップに変換したいと思います。
var ys = Immutable.fromJS({k: {key: "k", text: "foo"}})
Immutable.jsでxs
をys
に慣用的に変換するにはどうすればよいですか?
によって慣用的に中間構造はすべてimmutable.js構造である必要があることを意味し、中間ステップでは 反復可能な構成 を使用すると思います=フルサイズの中間表現を作成する代わりに。
編集:私は jsperfベンチマーク を作成して、これまでに提供された回答を比較します。どちらの非変異ソリューションも、私にはかなり慣用的な感じがします。投票を選んで答えを決定させるか、ほぼ同じように慣用的な手法のコレクションを収集できるようになるまで保留します。
入力リストを新しいImmutable.Mapに減らすことができます。
var ys = xs.reduce(
function(result, item) { return result.set(item.get('key'), item); },
Immutable.Map());
この場合、中間表現はありませんが、不変マップはすべての反復で更新する必要があり(実際、新しいインスタンスを作成する必要があります)、それは最適ではない可能性があります(Immutable.Mapの実際の実装によって異なります)。
通常のjavascriptオブジェクトに縮小して最適化し、最後に不変マップに変換できます。
var ys = Immutable.Map(xs.reduce(
function(result, item) { result[item.get('key')] = item; return result; },
{}));
しかし、それは確かにあまり慣用的ではありません。
1つの解決策は、リストからマップコンストラクターを使用することです。
const ys = Immutable.Map(xs.map(v => [v.get('key'), v]));
このようですが、中間表現についてはわかりません
ys = Immutable
.fromJS([{key:'k', value:'xxx'}])
.toKeyedSeq()
.mapEntries(function (kv) { return [kv[1].get('key'), kv[1]]; })
PSそれは奇妙ですが、私は.toKeyedSeqのみを使用でき、.toKeyedIterableではなく、より適切です。
reduce
とmergeWith
を組み合わせて使用すると、マップのリストをリストのマップに交換できます。
コレクション全体を削減し、値を連結して新しいアイテムをマージします。
collection.reduce((rr, ii) => rr.mergeWith((aa, bb) => List().concat(aa, bb), ii))