Edited at

forEachを使わずフラットなデータをツリーデータにする

なんとなくArray.prototype.forEachやjQueryのeachを使って再帰関数を回していたのですが、「JavaScript で forEach を使うのは最終手段」という記事を読み、少し考えを改めてみようと思いました。

しかしparent_idというプロパティを持つフラットなデータを読み込み、それをツリー型にしてみたいと思った時、あれ?と考え込みました。

うーん、forEachつかわず再帰処理させつつデータを作り直すってどうやるんだ・・・


とりあえず何も考えず書いたコード

let func = (obj) => {

obj.items = Object.assign([], master_categories.filter(category =>
category.parent_id === obj.category_id))
obj.items.forEach(func)
}
let categories = Object.assign([], master_categories.filter(category => !category.parent_id))
categories.forEach(func)
//読みにくいかもですが、filter()は実体参照するのでassign()でオブジェクトを複製してます


Array.prototype.mapを使う

forEachよりはマシなのだろうか?

本来はこんな使い方をする関数ではなさそうですが、ひとまずはperlっぽくmapを使うことに。

let func = (obj) => {

let robj = Object.assign({}, obj)
robj.items = master_categories.filter(category =>
category.parent_id && category.parent_id === robj.category_id).map(func)
return robj
}
let categories = master_categories.filter(category => !category.parent_id).map(func)

もっと賢いやり方がありそうですが、ひとまずこれで妥協することに。


追記

一応それっぽいですが、なにか優位だと言える証拠をみつけたかったのでGoogle(他力)にすがってみました。

参考:JavaScript — Map vs. ForEach(codeburst.io)

このサイトの検証結果ではforEachmapより70%も遅いという結果がでたそうです。