列A | 列B | 列C |
---|---|---|
A-1 | B-1 | C-1 |
A-1 | B-1 | C-2 |
A-1 | B-2 | C-3 |
A-1 | B-2 | C-4 |
A-2 | B-3 | C-5 |
A-2 | B-3 | C-6 |
A-2 | B-4 | C-7 |
A-2 | B-4 | C-8 |
A-1 | B-5 | C-9 |
A-2 | B-2 | C-10 |
このような配列を
javascript
1[ 2 [ '列A', '列B', '列C' ], 3 [ 'A-1', 'B-1', 'C-1' ], 4 [ 'A-1', 'B-1', 'C-2' ], 5 〜〜〜〜 6]
以下のようなツリー構造に変換したい
json
1[ 2 { 3 "列A": "A-1", 4 "list": [ 5 { 6 "列B": "B-1", 7 "list": [ 8 "C-1", 9 "C-2" 10 ] 11 }, 12 { 13 "列B": "B-2", 14 "list": [ 15 "C-3", 16 "C-4" 17 ] 18 }, 19 { 20 "列B": "B-5", 21 "list": [ 22 "C-9" 23 ] 24 } 25 ] 26 }, 27 { 28 "列A": "A-2", 29 "list": [ 30 { 31 "列B": "B-3", 32 "list": [ 33 "C-5", 34 "C-6" 35 ] 36 }, 37 { 38 "列B": "B-4", 39 "list": [ 40 "C-7", 41 "C-8" 42 ] 43 }, 44 { 45 "列B": "B-2", 46 "list": [ 47 "C-10" 48 ] 49 } 50 ] 51 } 52]
map
とfilter
を多数ネストしできなくもないですが、行列が変更になっても対応できるアルゴリズムが知りたいです。
解決案
javascript
1const tableToTreeObjArr = (tableData, childListKey) => { 2 3 // ヘッダー取得 4 const header = tableData[0] 5 6 // 行単位の処理 7 const addRowToTree = (treeArray, row, header) => { 8 9 let list = treeArray 10 11 for (let i = 0; i < row.length; ++ i) { 12 13 // 最終列以外 子配列を格納する親オブジェクトを生成 14 if (i < row.length - 1) { 15 16 // ヘッダーから列名取得 17 const key = header[i] 18 19 // 親オブジェクトがまだ存在しない場合は生成 20 let obj = list.find(col => { 21 return col[key] === row[i] 22 }) 23 if (!obj) { 24 obj = { [key]: row[i], [childListKey]: [] } 25 list.push(obj) 26 } 27 28 // list変数の参照先を子配列に変更 29 list = obj[childListKey] 30 31 // 最終列 子配列への格納のみ行う 32 } else { 33 list.push(row[i]) 34 } 35 } 36 37 return treeArray 38 } 39 40 // ヘッダー以降の行を配列に畳み込み 41 return tableData.slice(1).reduce((treeArray, row) => { 42 return addRowToTree(treeArray, row, header) 43 }, []) 44}
とりあえず、表の1行目に "list" があると破綻する構造です。
ご確認いただきありがとうございます。
確かにキーが重複してしまいますね。。。
実用的にする為にこの点もハンドリングすることを後ほど検討してみます。
Q1. アイデアは有りますが、知りたいのはコードではなく、アルゴリズムという事で良いのですね?
Q2. どのあたりまでご自身で考えられましたか。
あなたの考えの軌跡を質問文に追記すると、回答が寄せられやすくなると思います。
>Q1. アイデアは有りますが、知りたいのはコードではなく、アルゴリズムという事で良いのですね?
はい。なぜ想定した結果を得ることができるのか、そのアルゴリズムを理解することが一番の目的です。
>Q2. どのあたりまでご自身で考えられましたか。
filterで1列目の重複を取り除き、1列目に属する行をmapで抽出し、また重複を取り除き、、、
とネストを繰り返し記述することで想定通りの結果を得ることはできたものの、行列の変更に耐えられる様に汎用化する上で、
ライブラリを探す?再帰的処理で検討する?関数型をもっと理解するべき?、、、と何から手をつけて良いか分からなくなり投稿させていただいた次第です。
うーん…、目的の結果を得られたのであれば、そう難しい問題ではないように思えるのですが…。
配列を前から順番に検索して、予め用意した空のオブジェクトのプロパティに代入するだけですよね?
どこが難しく感じるのでしょうか。
(私はライブラリを使用しなくても実装できると思います)
回答3件
あなたの回答
tips
プレビュー