teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

12

テキスト修正

2020/06/20 10:08

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -200,4 +200,24 @@
200
200
 
201
201
  - C-10 の親は B-2 で、B-2 の親は A-2
202
202
 
203
- となってしまい、B-2 には、二つの親、A-1 と A-2 があることになってしまいます。ですが、先のstackoverflow の投稿では、各ノードの親は、木構造の定義に沿って、(最大で)一個であるようなノードの一次元配列を木構造化するコードでした。これを踏まえて、それでも[ベストアンサー](https://stackoverflow.com/a/18018037) の `function list_to_tree(list)` を使おうとすると、id として A-1やB-2だったりの文字列はそのまま使えず、「A-1 が親のB-1 と、A-2が親のB-2とは、別物である」という考え方を採り入れて、それらに異なる id を設ける必要があり、これはけっこう煩雑な作業となりそうです。
203
+ となってしまい、B-2 には、二つの親、A-1 と A-2 があることになってしまいます。ですが、先のstackoverflow の投稿では、各ノードの親は、木構造の定義に沿って、(最大で)一個であるようなノードの一次元配列を木構造化するコードでした。これを踏まえて、それでも[ベストアンサー](https://stackoverflow.com/a/18018037) の `function list_to_tree(list)` を使おうとすると、id として A-1やB-2だったりの文字列はそのまま使えず、「A-1 が親のB-1 と、A-2が親のB-2とは、別物である」という考え方を採り入れて、それらに異なる id を設ける必要があり、これはけっこう煩雑な作業となりそうです。
204
+
205
+ ### 追記4
206
+
207
+ 上記の追記3で書いた、[function list_to_tree(list)](https://stackoverflow.com/a/18018037) を使うための
208
+
209
+ > 「A-1 が親のB-1 と、A-2が親のB-2とは、別物である」という考え方を採り入れて、それらに異なる id
210
+
211
+ を実装したコード例を挙げておきます。以下になります。(※ `list_to_tree(list)` は、そのままコピペしてきたもので、手を加えていません)
212
+
213
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/zYrNQzv?editors=0012](https://codepen.io/jun68ykt/pen/zYrNQzv?editors=0012)
214
+
215
+ 具体的には、たとえば、`[ 'A-2', 'B-2', 'C-10' ]` の `C-10` から、以下のようなノードオブジェクトを作成します。
216
+ ```javascript
217
+ { id: 'A-2/B-2/C-10', parentId: 'A-2/B-2', label: 'C-10' }
218
+ ```
219
+ また、トップレベルの `A-2` からは、 parentId に文字列の `"0"` を入れた、以下のオブジェクトを作成します。
220
+ ```javascript
221
+ { id: 'A-2', parentId: '0', label: 'A-2' }
222
+ ```
223
+ 上記のようなオブジェクトを要素とする一次元配列を、元のテーブルデータから作成すると、その配列を [function list_to_tree(list)](https://stackoverflow.com/a/18018037) に渡すことができて、木構造化した配列を返してくれますので、それをさらに望ましい形にフォーマットして結果を得ています。

11

テキスト修正

2020/06/20 10:08

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -170,4 +170,34 @@
170
170
  console.log(JSON.stringify(treeArray, null, 2));
171
171
  ```
172
172
 
173
- - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/oNbBaKE?editors=0012](https://codepen.io/jun68ykt/pen/oNbBaKE?editors=0012)
173
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/oNbBaKE?editors=0012](https://codepen.io/jun68ykt/pen/oNbBaKE?editors=0012)
174
+
175
+ ### 追記3
176
+
177
+ 先に書いた、追記1 で、stackoverflow の投稿 [Build tree array from flat array in javascript](https://stackoverflow.com/questions/18017869) を挙げましたが、これの回答の中の[ベストアンサー](https://stackoverflow.com/a/18018037) の `function list_to_tree(list)` を使えそうか、ちょっとスパイクしてみましたが、問題があり簡単にはできそうもなかったです。その説明を以下、記載します。
178
+
179
+ 元のテーブルのデータ配列は
180
+ ```
181
+ [
182
+ [ '列A', '列B', '列C' ],
183
+ [ 'A-1', 'B-1', 'C-1' ],
184
+ [ 'A-1', 'B-1', 'C-2' ],
185
+ [ 'A-1', 'B-2', 'C-3' ],
186
+ [ 'A-1', 'B-2', 'C-4' ],
187
+ [ 'A-2', 'B-3', 'C-5' ],
188
+ [ 'A-2', 'B-3', 'C-6' ],
189
+ [ 'A-2', 'B-4', 'C-7' ],
190
+ [ 'A-2', 'B-4', 'C-8' ],
191
+ [ 'A-1', 'B-5', 'C-9' ],
192
+ [ 'A-2', 'B-2', 'C-10' ]
193
+ ]
194
+ ```
195
+ というものですが、これのデータ行の3行目 `[ 'A-1', 'B-2', 'C-3' ]` を、ツリー末端の子(葉)のほうから親のほうへ向かうパスとして読むと
196
+
197
+ - C-3 の親は B-2 で、B-2 の親は A-1
198
+
199
+ と読めるのですが、そうすると、最後の行の `[ 'A-2', 'B-2', 'C-10' ]` は
200
+
201
+ - C-10 の親は B-2 で、B-2 の親は A-2
202
+
203
+ となってしまい、B-2 には、二つの親、A-1 と A-2 があることになってしまいます。ですが、先のstackoverflow の投稿では、各ノードの親は、木構造の定義に沿って、(最大で)一個であるようなノードの一次元配列を木構造化するコードでした。これを踏まえて、それでも[ベストアンサー](https://stackoverflow.com/a/18018037) の `function list_to_tree(list)` を使おうとすると、id として A-1やB-2だったりの文字列はそのまま使えず、「A-1 が親のB-1 と、A-2が親のB-2とは、別物である」という考え方を採り入れて、それらに異なる id を設ける必要があり、これはけっこう煩雑な作業となりそうです。

10

テキスト修正

2020/06/20 08:02

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -1,6 +1,6 @@
1
1
  こんにちは
2
2
 
3
- いろいろなやり方がありそうですが、一例を回答します。以下の二次元配列 `tableData` から目的のJSONを得るコードを挙げます
3
+ いろいろなやり方がありそうですが、一例を回答します。以下の二次元配列 `tableData` から目的のJSONを得るコードを挙げます
4
4
  ```javascript
5
5
  const tableData = [
6
6
  [ '列A', '列B', '列C' ],
@@ -16,7 +16,7 @@
16
16
  [ 'A-2', 'B-2', 'C-10' ]
17
17
  ];
18
18
  ```
19
- 上記の配列`tableData`から、階層構造を復元したオブジェクトを作ります。その際に lodash の [_.set](https://lodash.com/docs/#set)を使います。
19
+ 上記の配列`tableData`から、階層構造を復元したオブジェクトを作ります。その際に lodash の [_.set](https://lodash.com/docs/#set) を使います。
20
20
 
21
21
  ```javascript
22
22
  const treeObj = tableData.slice(1).reduce((obj, path) => _(obj).set(path, null).value(), {});
@@ -134,7 +134,7 @@
134
134
  以上参考になれば幸いです。
135
135
 
136
136
 
137
- ### 追記
137
+ ### 追記1
138
138
 
139
139
  別案を検討する際の参考情報です。一次元のオブジェクト配列から、オブジェクト間の階層構造を復元した配列に変換するコードの例は
140
140
 

9

テキスト修正

2020/06/20 05:12

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -165,7 +165,7 @@
165
165
  return treeArray;
166
166
  };
167
167
 
168
- const treeArray = tableData.slice(1).reduce((ary, row) => addRowToTree(ary, row), []);
168
+ const treeArray = tableData.slice(1).reduce((tree, row) => addRowToTree(tree, row), []);
169
169
 
170
170
  console.log(JSON.stringify(treeArray, null, 2));
171
171
  ```

8

テキスト修正

2020/06/20 03:36

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -148,18 +148,18 @@
148
148
 
149
149
  ```javascript
150
150
  const addRowToTree = (treeArray, row) => {
151
- let ary = treeArray;
151
+ let list = treeArray;
152
152
  for (let i=0; i < row.length; ++ i) {
153
153
  if (i < row.length-1) {
154
154
  const key = `列${row[i][0]}`;
155
- let obj = ary.find(e => e[key] === row[i]);
155
+ let obj = list.find(e => e[key] === row[i]);
156
156
  if (!obj) {
157
157
  obj = { [key]: row[i], list: [] };
158
- ary.push(obj);
158
+ list.push(obj);
159
159
  }
160
- ary = obj.list;
160
+ list = obj.list;
161
161
  } else {
162
- ary.push(row[i]);
162
+ list.push(row[i]);
163
163
  }
164
164
  }
165
165
  return treeArray;

7

テキスト修正

2020/06/19 20:58

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -147,7 +147,7 @@
147
147
  オブジェクトを経由しない別案を作成しました。こちらは、どの階層においても、元のテーブルでの出現順にリストされます。
148
148
 
149
149
  ```javascript
150
- const addRow = (treeArray, row) => {
150
+ const addRowToTree = (treeArray, row) => {
151
151
  let ary = treeArray;
152
152
  for (let i=0; i < row.length; ++ i) {
153
153
  if (i < row.length-1) {
@@ -165,7 +165,7 @@
165
165
  return treeArray;
166
166
  };
167
167
 
168
- const treeArray = tableData.slice(1).reduce((ary, row) => addRow(ary, row), []);
168
+ const treeArray = tableData.slice(1).reduce((ary, row) => addRowToTree(ary, row), []);
169
169
 
170
170
  console.log(JSON.stringify(treeArray, null, 2));
171
171
  ```

6

テキスト修正

2020/06/19 20:51

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -151,7 +151,7 @@
151
151
  let ary = treeArray;
152
152
  for (let i=0; i < row.length; ++ i) {
153
153
  if (i < row.length-1) {
154
- const key = `列${row[i][0]}`
154
+ const key = `列${row[i][0]}`;
155
155
  let obj = ary.find(e => e[key] === row[i]);
156
156
  if (!obj) {
157
157
  obj = { [key]: row[i], list: [] };

5

テキスト修正

2020/06/19 20:47

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -140,4 +140,34 @@
140
140
 
141
141
  - stackoverflow [Build tree array from flat array in javascript](https://stackoverflow.com/questions/18017869)
142
142
 
143
- にいくつか出ています。ご質問にある表データの配列を加工して、上記に投稿されているいずれかの回答コードをベースにした階層化コードを作成する手もあるかもしれません。
143
+ にいくつか出ています。ご質問にある表データの配列を加工して、上記に投稿されているいずれかの回答コードをベースにした階層化コードを作成する手もあるかもしれません。
144
+
145
+ ### 追記2
146
+
147
+ オブジェクトを経由しない別案を作成しました。こちらは、どの階層においても、元のテーブルでの出現順にリストされます。
148
+
149
+ ```javascript
150
+ const addRow = (treeArray, row) => {
151
+ let ary = treeArray;
152
+ for (let i=0; i < row.length; ++ i) {
153
+ if (i < row.length-1) {
154
+ const key = `列${row[i][0]}`
155
+ let obj = ary.find(e => e[key] === row[i]);
156
+ if (!obj) {
157
+ obj = { [key]: row[i], list: [] };
158
+ ary.push(obj);
159
+ }
160
+ ary = obj.list;
161
+ } else {
162
+ ary.push(row[i]);
163
+ }
164
+ }
165
+ return treeArray;
166
+ };
167
+
168
+ const treeArray = tableData.slice(1).reduce((ary, row) => addRow(ary, row), []);
169
+
170
+ console.log(JSON.stringify(treeArray, null, 2));
171
+ ```
172
+
173
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/oNbBaKE?editors=0012](https://codepen.io/jun68ykt/pen/oNbBaKE?editors=0012)

4

テキスト修正

2020/06/19 20:43

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -53,28 +53,15 @@
53
53
  }
54
54
  }
55
55
  ```
56
- この`treeObj` から、目的の配列を得るための再帰関数 `treeObjToArray` と、これの中で使うソート用の比較関数 `keyCompare` を作成します。
56
+ この`treeObj` から、目的の配列を得るための再帰関数 `treeObjToArray` を作成します。
57
57
 
58
58
  ```javascript
59
- const keyCompare = (k1, k2) => {
60
- const ch1 = k1[0], ch2 = k2[0];
61
- const n1 = +k1.substring(2), n2 = +k2.substring(2);
62
- return ch1 !== ch2 ? ch1.localeCompare(ch2) : n1 - n2;
63
- }
64
-
65
- ```
66
- 上記の `keyCompare` は、セルの文字列を以下のように順序づけます。
67
-
68
- `A-1` < `A-2` < `B-2` < `B-10` < `C-1`
69
-
70
- `treeObj` から、目的の配列を得るための再帰関数 `treeObjToArray`は以下です。
71
- ```javascript
72
59
  const treeObjToArray = obj => {
73
- const entries = Object.entries(obj).sort(([k1], [k2]) => keyCompare(k1, k2));
60
+ const entries = Object.entries(obj).sort(([k1], [k2]) => k1.substring(2) - k2.substring(2));
74
61
  return entries.map(([k, v]) => ({
75
62
  [`列${k[0]}`]: k,
76
63
  list: Object.values(v)[0] ?
77
- treeObjToArray(v) : Object.keys(v).sort((k1, k2) => keyCompare(k1, k2))
64
+ treeObjToArray(v) : Object.keys(v).sort((k1, k2) => k1.substring(2) - k2.substring(2))
78
65
  })
79
66
  );
80
67
  }
@@ -142,7 +129,7 @@
142
129
  ]
143
130
  ```
144
131
 
145
- - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/wvMgYMX?editors=0012](https://codepen.io/jun68ykt/pen/wvMgYMX?editors=0012)
132
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/KKVaGXj?editors=0012](https://codepen.io/jun68ykt/pen/KKVaGXj?editors=0012)
146
133
 
147
134
  以上参考になれば幸いです。
148
135
 

3

テキスト修正

2020/06/19 19:27

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -19,7 +19,7 @@
19
19
  上記の配列`tableData`から、階層構造を復元したオブジェクトを作ります。その際に lodash の [_.set](https://lodash.com/docs/#set)を使います。
20
20
 
21
21
  ```javascript
22
- const treeObj = tableData.slice(1).reduce((o, path) => _(o).set(path, null).value(), {});
22
+ const treeObj = tableData.slice(1).reduce((obj, path) => _(obj).set(path, null).value(), {});
23
23
  ```
24
24
  上記によって、`treeObj` に下記のようなオブジェクトが得られます。
25
25
 

2

テキスト修正

2020/06/19 19:18

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -1,31 +1,9 @@
1
1
  こんにちは
2
2
 
3
- いろいろなやり方がありそうですが、一例を挙げておきます。
4
-
5
- この回答、以下のような、空白文字で区切られたテキストとして与えられた表データから目的のJSONを得るコードを挙げます
3
+ いろいろなやり方がありそうすが一例を回答します。以下の二次元配列 `tableData` から目的のJSONを得るコードを挙げます
6
-
7
4
  ```javascript
8
- const tableText =
5
+ const tableData = [
9
- `列A 列B 列C
10
- A-1 B-1 C-1
11
- A-1 B-1 C-2
12
- A-1 B-2 C-3
13
- A-1 B-2 C-4
14
- A-2 B-3 C-5
15
- A-2 B-3 C-6
16
- A-2 B-4 C-7
17
- A-2 B-4 C-8
18
- A-1 B-5 C-9
19
- A-2 B-2 C-10`;
20
- ```
21
-
22
- 以下によって、各セルの値の配列を得ます。
23
- ```javascript
24
- const tableData = tableText.split('\n').map(str => str.trim().split(/\s+/)).splice(1);
6
+ [ '列A', '列B', '列C' ],
25
- ```
26
- 上記によって、 `tableData` は、以下のような二次元配列になります。
27
- ```javascript
28
- [
29
7
  [ 'A-1', 'B-1', 'C-1' ],
30
8
  [ 'A-1', 'B-1', 'C-2' ],
31
9
  [ 'A-1', 'B-2', 'C-3' ],
@@ -36,12 +14,12 @@
36
14
  [ 'A-2', 'B-4', 'C-8' ],
37
15
  [ 'A-1', 'B-5', 'C-9' ],
38
16
  [ 'A-2', 'B-2', 'C-10' ]
39
- ]
17
+ ];
40
18
  ```
41
19
  上記の配列`tableData`から、階層構造を復元したオブジェクトを作ります。その際に lodash の [_.set](https://lodash.com/docs/#set)を使います。
42
20
 
43
21
  ```javascript
44
- const treeObj = tableData.reduce((o, path) => _(o).set(path, null).value(), {});
22
+ const treeObj = tableData.slice(1).reduce((o, path) => _(o).set(path, null).value(), {});
45
23
  ```
46
24
  上記によって、`treeObj` に下記のようなオブジェクトが得られます。
47
25
 
@@ -164,7 +142,7 @@
164
142
  ]
165
143
  ```
166
144
 
167
- - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/JjGEBgx?editors=0012](https://codepen.io/jun68ykt/pen/JjGEBgx?editors=0012)
145
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/wvMgYMX?editors=0012](https://codepen.io/jun68ykt/pen/wvMgYMX?editors=0012)
168
146
 
169
147
  以上参考になれば幸いです。
170
148
 

1

テキスト修正

2020/06/19 19:03

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -87,9 +87,8 @@
87
87
  ```
88
88
  上記の `keyCompare` は、セルの文字列を以下のように順序づけます。
89
89
 
90
- `A-1` < `A-2` < `B-1` < `B-10` < `C-1`
90
+ `A-1` < `A-2` < `B-2` < `B-10` < `C-1`
91
91
 
92
-
93
92
  `treeObj` から、目的の配列を得るための再帰関数 `treeObjToArray`は以下です。
94
93
  ```javascript
95
94
  const treeObjToArray = obj => {
@@ -167,4 +166,13 @@
167
166
 
168
167
  - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/JjGEBgx?editors=0012](https://codepen.io/jun68ykt/pen/JjGEBgx?editors=0012)
169
168
 
170
- 以上参考になれば幸いです。
169
+ 以上参考になれば幸いです。
170
+
171
+
172
+ ### 追記
173
+
174
+ 別案を検討する際の参考情報です。一次元のオブジェクト配列から、オブジェクト間の階層構造を復元した配列に変換するコードの例は
175
+
176
+ - stackoverflow [Build tree array from flat array in javascript](https://stackoverflow.com/questions/18017869)
177
+
178
+ にいくつか出ています。ご質問にある表データの配列を加工して、上記に投稿されているいずれかの回答コードをベースにした階層化コードを作成する手もあるかもしれません。