質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

3回答

1656閲覧

配列での重複確認と重複したものを格納していく処理

ktak11

総合スコア5

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2019/09/03 03:11

前提・実現したいこと

下記の配列で重複チェックを行い処理を行いたいのですが、

JavaScript

1let Records = [ 2 { 3 A: { type: "DROP_DOWN", value: null }, 4 B: { type: "NUMBER", value: "100" }, 5 C: { type: "DROP_DOWN", value: null }, 6 D: { type: "DROP_DOWN", value: "TEST1" }, 7 E: { type: "SINGLE_LINE_TEXT", value: "" }, 8 F: { type: "SINGLE_LINE_TEXT", value: "TEST2" }, 9 G: { type: "SINGLE_LINE_TEXT", value: "5" }, 10 H: { type: "DATE", value: "2019-09-01" }, 11 I: { type: "DROP_DOWN", value: "TEST3" }, 12 J: { type: "NUMBER", value: "10000" }, 13 K: { type: "SINGLE_LINE_TEXT", value: "001" } 14 }, 15 { 16 A: { type: "DROP_DOWN", value: null }, 17 B: { type: "NUMBER", value: "10000" }, 18 C: { type: "DROP_DOWN", value: null }, 19 D: { type: "DROP_DOWN", value: "TEST4" }, 20 E: { type: "SINGLE_LINE_TEXT", value: "" }, 21 F: { type: "SINGLE_LINE_TEXT", value: "TEST5" }, 22 G: { type: "SINGLE_LINE_TEXT", value: "5" }, 23 H: { type: "DATE", value: "2019-09-01" }, 24 I: { type: "DROP_DOWN", value: "TEST6" }, 25 J: { type: "NUMBER", value: "10000" }, 26 K: { type: "SINGLE_LINE_TEXT", value: "002" } 27 }, 28 { 29 A: { type: "DROP_DOWN", value: null }, 30 B: { type: "NUMBER", value: "1000" }, 31 C: { type: "DROP_DOWN", value: null }, 32 D: { type: "DROP_DOWN", value: "TEST7" }, 33 E: { type: "SINGLE_LINE_TEXT", value: "" }, 34 F: { type: "SINGLE_LINE_TEXT", value: "TEST8" }, 35 G: { type: "SINGLE_LINE_TEXT", value: "5" }, 36 H: { type: "DATE", value: "2019-09-01" }, 37 I: { type: "DROP_DOWN", value: "TEST9" }, 38 J: { type: "NUMBER", value: "10000" }, 39 K: { type: "SINGLE_LINE_TEXT", value: "001" } 40 } 41];

①重複しているものを除いて抽出(Kのvalue値で重複チェックする)
②その後、重複したものは①のLを追加し配列に格納していく

といった方法をとりたく、最終的には下記の実現を望んでいます。

JavaScript

1let Records = [ 2 { 3 A: { type: "DROP_DOWN", value: null }, 4 B: { type: "NUMBER", value: "100" }, 5 C: { type: "DROP_DOWN", value: null }, 6 D: { type: "DROP_DOWN", value: "TEST1" }, 7 E: { type: "SINGLE_LINE_TEXT", value: "" }, 8 F: { type: "SINGLE_LINE_TEXT", value: "TEST2" }, 9 G: { type: "SINGLE_LINE_TEXT", value: "5" }, 10 H: { type: "DATE", value: "2019-09-03" }, 11 I: { type: "DROP_DOWN", value: "TEST3" }, 12 J: { type: "NUMBER", value: "10000" }, 13 K: { type: "SINGLE_LINE_TEXT", value: "001" }, 14     //追加部分 15 L: [{ 16 A: { type: "DROP_DOWN", value: null }, 17 B: { type: "NUMBER", value: "1000" }, 18 C: { type: "DROP_DOWN", value: null }, 19 D: { type: "DROP_DOWN", value: "TEST7" }, 20 E: { type: "SINGLE_LINE_TEXT", value: "" }, 21 F: { type: "SINGLE_LINE_TEXT", value: "TEST8" }, 22 G: { type: "SINGLE_LINE_TEXT", value: "5" }, 23 H: { type: "DATE", value: "2019-09-03" }, 24 I: { type: "DROP_DOWN", value: "TEST9" }, 25 J: { type: "NUMBER", value: "10000" }, 26 K: { type: "SINGLE_LINE_TEXT", value: "001" } 27 }] 28 }, 29 { 30 A: { type: "DROP_DOWN", value: null }, 31 B: { type: "NUMBER", value: "10000" }, 32 C: { type: "DROP_DOWN", value: null }, 33 D: { type: "DROP_DOWN", value: "TEST4" }, 34 E: { type: "SINGLE_LINE_TEXT", value: "" }, 35 F: { type: "SINGLE_LINE_TEXT", value: "TEST5" }, 36 G: { type: "SINGLE_LINE_TEXT", value: "5" }, 37 H: { type: "DATE", value: "2019-09-03" }, 38 I: { type: "DROP_DOWN", value: "TEST6" }, 39 J: { type: "NUMBER", value: "10000" }, 40 K: { type: "SINGLE_LINE_TEXT", value: "002" }, 41 } 42];

試したこと

JavaScript

1let results = Records.reduce((res, cur) => { 2 for (let i = 0, s = res.length, name = cur.K.value, object; i < s; ++i) { 3 object = res[i]; 4 if (object.K.value === name) {return res;} 5 } 6 res.push(cur); 7 return res; 8}, []);

これで、上記の①の部分は出来ていると思うのですが②の部分をどの様にしていけば良いか悩んでいます。ご教授頂けましたら幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2019/09/03 03:17

重複のチェックはKだけでOKですね? 常に0番目の要素と1番目以降の要素を比較するんでしょうか? たとえば0番目の要素にマッチしなかったとして 1番目と2番目の要素を比較する必要はない?
ktak11

2019/09/03 03:24

ご返信ありがとうございます。 ```重複のチェックはKだけでOKですね?``` はい。Kだけを参照して重複の判断をします。 ```常に0番目の要素と1番目以降の要素を比較するんでしょうか?常に0番目の要素と1番目以降の要素を比較するんでしょうか?たとえば0番目の要素にマッチしなかったとして1番目と2番目の要素を比較する必要はない?``` 1番目と2番目の要素を比較する必要ございます。
Lhankor_Mhy

2019/09/03 04:09

補足願います。 { A: { type: "DROP_DOWN", value: null }, B: { type: "NUMBER", value: "100" }, ... L: [{ A: { type: "DROP_DOWN", value: null }, B: { type: "NUMBER", value: "1000" }, ... }] }, ↑これは、↓これでもいいのですか? { A: { type: "DROP_DOWN", value: null }, B: { type: "NUMBER", value: "1000" }, ... L: [{ A: { type: "DROP_DOWN", value: null }, B: { type: "NUMBER", value: "100" }, ... }] }, つまり、Lを増やすオブジェクトと、増やしたLに入れるオブジェクトとは、ご提示の手順ですと区別がつかないようですが、それらの関係は任意で構いませんか?
jun68ykt

2019/09/03 04:13

処理の一部に外部のライブラリを使うことは、回答としてアリでしょうか?
jun68ykt

2019/09/03 15:52

先の当方からのご質問、 > 処理の一部に外部のライブラリを使うことは、回答としてアリでしょうか? にまだご返答頂いておりませんが、Lodash の groupBy を使うとRecordsから最終的に欲しいresuls を得るコードを手短かに書けるので、参考までに、これを使ったコード例もあわせて回答しました。
guest

回答3

0

KとL以外関係なさそうなのでほかは省略してAだけダミーを置きました

javascript

1let Records = [ 2 {A:1, K: { type: "SINGLE_LINE_TEXT", value: "001" }}, 3 {A:2, K: { type: "SINGLE_LINE_TEXT", value: "002" }}, 4 {A:3, K: { type: "SINGLE_LINE_TEXT", value: "001" }}, 5 {A:4, K: { type: "SINGLE_LINE_TEXT", value: "002" }}, 6 {A:5, K: { type: "SINGLE_LINE_TEXT", value: "003" }}, 7 {A:6, K: { type: "SINGLE_LINE_TEXT", value: "002" }}, 8]; 9var rec={}; 10Records.forEach((x,y)=>{ 11 var k=JSON.stringify(x.K); 12 if(typeof rec[k]=="undefined") rec[k]=[]; 13 rec[k].push(y); 14}); 15for(var i=Records.length-1;i>=0;i--){ 16 var k=JSON.stringify(Records[i].K); 17 var r=rec[k][0]; 18 if(r!==i){ 19 if(typeof Records[r].L=="undefined") Records[r].L=[]; 20 Records[r].L.push(Records.splice(i,1)); 21 } 22} 23</script>

投稿2019/09/03 04:06

編集2019/09/03 04:06
yambejp

総合スコア114581

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ktak11

2019/09/04 04:51 編集

返信大変遅くなりまして、申し訳ありません。 また、本件に対しご貴重なお時間を費やしてくださり、お答え頂きとても感謝致します。 内容全て見れておりませんが、勉強させて頂きます。ありがとうございます。
guest

0

ベストアンサー

こんにちは

この回答では、以下の(1)、(2)、(3)の3つのコードを示します。

(1) ご質問で問われている②のコード例

ご質問に

上記の①の部分は出来ていると思うのですが②の部分をどの様にしていけば良いか悩んでいます。

とありましたので、ご質問に挙げられている、①の部分のコードには手を加えず、①に続く②の部分のコード例を挙げます。

(2) Lodash を使ったコード例

配列の操作で便利なメソッドを提供するライブラリ Lodash を使って、Records から直接、最終的に欲しい形で results を得るコードを挙げます。

** (3)ご質問に挙げられている①の部分のコードを修正したもの **

ご質問に挙げられている、①の部分のコードを修正して、①を行いながら②も併せて行うようにします。(この回答の最後に、追記2 として記載しています)

(1) ご質問で問われている②のコード例

以下に処理の概要を示します。

  1. Records の要素を、先頭から最後までのループで取得。各要素を e、そのインデクスを iとする。
  2. 処理①によって得られたresults の要素oの中で、 o.K.value の値が e.K.value と等しい要素をみつけ、これを objとする。
  3. もし obj.L が undefined であれば 空の配列を入れておく。
  4. Records の要素oの中で、 o.K.value の値が e.K.valueと等しいもののうち、最も先頭に近い要素のインデクスを index とする。
  5. iindex よりも大きければ、 eobj.Lに追加する。
  6. また、上記で、2. と 4. の検索を、毎回行うのは無駄なので、一度、objindex を取得した e.K.value については、再度の検索を不要にするために、適当なオブジェクトにキャッシュしておく。

以下は、上記をコードにしたものです。ご質問にある①のコードに続く、②だけのコードです。

javascript

1const cache = {}; // 上記 6. のキャッシュオブジェクト 2 3Records.forEach((e, i) => { 4 const { value } = e.K; 5 let info = cache[value]; // キャッシュにすでに情報があれば取得 6 if (!info) { // キャッシュにない場合、 7 const obj = results.find(o => o.K.value === value); // 上記 2. の検索 8 obj.L = []; // ここでは、obj.L は undefined なので空配列を入れておく。 9 const index = Records.findIndex(o => o.K.value === value); // 上記 4. の検索 10 info = { obj, index }; // キャッシュするオブジェクトを作り、 11 cache[value] = info; // value をキーにして、 obj と index を入れておく。 12 } 13 if (i > info.index) // 上記、 5. の処理 14 info.obj.L.push(e); 15});

上記のコードを試すために、Codepen に動作確認できるものを作成しました。

なお、上記のサンプルでは

  • 処理 ① の部分はご質問に挙げられているコードそのままです。
  • 動作確認をしやすくするために、 Records の各要素は、ユニークな id プロパティを持ち、 K プロパティは valueのみを持つオブジェクトとし、 idK以外は省略して、以下のようにしました。

javascript

1let Records = [ 2 { id: 0, K: { value: "001" } }, 3 { id: 1, K: { value: "002" } }, 4 { id: 2, K: { value: "001" } }, 5 { id: 3, K: { value: "003" } }, 6 { id: 4, K: { value: "001" } }, 7 { id: 5, K: { value: "003" } }, 8 { id: 6, K: { value: "004" } }, 9 { id: 7, K: { value: "001" } }, 10 { id: 8, K: { value: "003" } }, 11 { id: 9, K: { value: "002" } } 12];

(2) Lodash を使ったコード例

配列の操作で便利なメソッドを提供するライブラリ Lodash_.groupBy というメソッドがあります。このメソッドは、配列の各要素を、要素に対する何らかの関数による値をキーとしてグルーピングしたオブジェクトを返してくれます。

今回のご質問の場合、Records の 各要素 e について、 e.K.value の値でグルーピングすればよいので、以下のようにします。

javascript

1_.groupBy(Records, e => e.K.value)

先ほどの動作確認用サンプルに使った Records を与えた場合、上記の _.groupBy によって返されるオブジェクトは、以下となります。

javascript

1{ 2 '001':[ 3 { id: 0, K: { value: "001" } }, 4 { id: 2, K: { value: "001" } }, 5 { id: 4, K: { value: "001" } }, 6 { id: 7, K: { value: "001" } } 7 ], 8 '002': [ 9 { id: 1, K: { value: "002" } }, 10 { id: 9, K: { value: "002" } } 11 ], 12 '003':[ 13 { id: 3, K: { value: "003" } }, 14 { id: 5, K: { value: "003" } }, 15 { id: 8, K: { value: "003" } } 16 ], 17 '004': [ 18 { id: 6, K: { value: "004" } } 19 ] 20}

この _.groupBy で返されるオブジェクトを使って、ご質問に書かれている要件のresults を得るには、以下のようにします。

javascript

1const results = Object.values( 2 _.groupBy(Records, e => e.K.value) 3 ).map(ary => ({ ...ary[0], L: ary.slice(1) }));

以上、参考になれば幸いです。

追記1

上記の回答で、 (2) に挙げたコードでは、一度グルーピングされたオブジェクトを作り、それに対して、Object.values() で配列を作り、その配列に対する .map()results を作っています。ですので、オブジェクトのエントリに順序はないことから、元のRecords の中での異なるvalue の出現順が、 results でも保たれる保証はないです。

もし、 Records での異なる valueの出現順が、 results での value の順番として保たれるようにするには、以下のようにします。

javascript

1// Recordsの要素に出現する value を、出現順に、かつ、重複を除いた配列を得る。 2const orderedValues = Records 3 .map(e => e.K.value) 4 .filter( 5 (v, i, values) => i === values.findIndex(v2 => v2 === v) 6 ); 7 8// value の値でグルーピングしたオブジェクトを得る。 9const groupsByValue = _.groupBy(Records, e => e.K.value); 10 11// orderedValues と groupsByValue から results を得る。 12const results = orderedValues.map(v => ({ 13 ...groupsByValue[v][0], 14 L: groupsByValue[v].slice(1) 15 }));

追記2

(3)ご質問に挙げられている①の部分のコードを修正したもの

以下のように、ご質問に挙げられている、①の部分のコードを少し修正して、②の処理も併せて行うようにすることもできます。

diff

1let results = Records.reduce((res, cur) => { 2 for (let i = 0, s = res.length, name = cur.K.value, object; i < s; ++i) { 3 object = res[i]; 4- if (object.K.value === name) {return res;} 5+ if (object.K.value === name) { 6+ object.L.push(cur); 7+ return res; 8+ } 9 } 10- res.push(cur); 11+ res.push({...cur, L:[] }); 12 return res; 13}, []);

投稿2019/09/03 15:47

編集2019/09/04 04:52
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ktak11

2019/09/04 04:51 編集

返信大変遅くなりまして、申し訳ありません。 また、本件に対しご貴重なお時間を費やしてくださり、お答え頂きとても感謝致します。 内容全て見れておりませんが、勉強させて頂きます。ありがとうございます。
jun68ykt

2019/09/04 04:51

どういたしまして。お役に立てましたら幸いです。
guest

0

重複したレコードがあれば、~~Lというプロパティが存在しないオブジェクトを見つけ、~~Lというプロパティに空の配列をセットし、そこにcurpushすれば良いです。

Javascript

1let results = Records.reduce((res, cur) => { 2 let duplicatedRecord = res.find(v => v.K.value === cur.K.value); 3 if (duplicatedRecord) { 4 if(!duplicatedRecord.L) duplicatedRecord.L = []; 5 duplicatedRecord.L.push(cur); 6 } else { 7 res.push(cur); 8 } 9 return res; 10}, []);

投稿2019/09/03 04:16

編集2019/09/03 04:25
BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BluOxy

2019/09/03 04:25 編集

13:23以前のコードだとLが配列ではないですね。要件通りに直しました。
ktak11

2019/09/04 04:51 編集

返信大変遅くなりまして、申し訳ありません。 また、本件に対しご貴重なお時間を費やしてくださり、お答え頂きとても感謝致します。 内容全て見れておりませんが、勉強させて頂きます。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問