私はRxJSチュートリアル http://reactivex.io/learnrx/ を行ってきました。ほとんどすべての演習は、階層構造からフラット構造への移行を伴うため、私は反対のことをしようと思いました。
チュートリアルの同じ機能構成体を使用して、各配列項目のプロパティに基づいてフラット配列からツリー構造に変換したいと思います。
つまりこれから行く:
var videos = [
{
"id": 70111470,
"title": "Die Hard",
"category": "Action"
},
{
"id": 654356453,
"title": "Bad Boys",
"category": "Action"
},
{
"id": 65432445,
"title": "Anchorman",
"category": "Comedy"
},
{
"id": 675465,
"title": "Everest",
"category": "New Release"
}
];
これには(各ビデオのカテゴリに基づく):
result === [
{
"category": "Action",
"videos": [
{
"id": 70111470,
"title": "Die Hard"
},
{
"id": 654356453,
"title": "Bad Boys"
}
]
},
{
"category": "Comedy",
"videos": [
{
"id": 65432445,
"title": "Anchorman"
}
]
},
{
"category": "New Release",
"videos": [
{
"id": 675465,
"title": "Everest"
}
]
}
];
機能する次のコードを考え出しましたが、(ビデオを何度もフィルタリングするのではなく)パフォーマンスが向上する簡単な方法(おそらく単一の削減で解決する)が足りないようです。
var result =
videos.reduce(function(catArray, video) {
var catName = video.category;
if (catArray.indexOf(catName) === -1) {
catArray.Push(catName);
}
return catArray;
}, [])
.map(function(categoryName) {
return {
category: categoryName,
videos: videos.filter(function(video) {
return video.category === categoryName;
}).map(function(video) {
return {
id: video.id,
title: video.title
};
})
};
});
関数型メソッドを使用するより良い方法はありますか?
結果はレベルを1つしか持てないため、ツリーよりも簡単です。必要なのは、配列をカテゴリ別にグループ化し、各グループをオブジェクトにマッピングすることだけです。マップパーツは、最終的な目的の構造に少し変更するだけです。現在行っているように、マップ内のvideos
の完全なリストをフィルタリングする必要はありません。
残念ながら、JavaScriptはデフォルトで機能パラダイムに特に友好的ではないので、組み込みgroupBy
がありません。そのため、reduce内でグループ化を再実装するか、 Ramda のような外部ライブラリからグループ化を使用できます。そこにあるサンプルコードは、groupBy
の仕組みを理解するのに役立ちます。