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

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

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

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

JavaScript

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

配列

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

Q&A

解決済

4回答

1250閲覧

配列の比較方法(ロジックを理解したいだけなので言語は特に問いません)

nanase21

総合スコア144

多次元配列

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

JavaScript

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

配列

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

0グッド

1クリップ

投稿2021/01/17 14:09

編集2021/01/17 14:56

実現したいこと

2つの多次元配列を比較し、配列の要素が一致していればtrueを返し、一致していなければfalseを返す関数の書き方について知りたいです

困っていること
純粋な配列であれば、比較する関数処理を書けるのですが、多次元配列のような配列の場合、どう比較し合う処理を書けば良いか分からずに困っています

js

1function compare(a, b){ 2 // 処理を書いていくのだが分からない... 3 return false; 4} 5// true 6const arrA = ["C", "E", ["B", "D", ["A"]]]; 7const arrB = ["C", "E", ["B", "D", ["A"]]]; 8console.log(compare(arrA, arrB)) 9// false: BとCの位置が異なっているため 10const arrC = ["C", "E", ["B", "D", ["A"]]]; 11const arrD = ["B", "E", ["C", "D", ["A"]]]; 12console.log(compare(arrC, arrD)) 13// false: Aが配列になっているかどうかを見ている 14const arrE = ["C", "E", ["B", "D", ["A"]]]; 15const arrF = ["C", "E", ["B", "D", "A"]]; 16console.log(compare(arrE, arrF))

JSON.stringifyを使った解

js

1// true 2const arrA = ["C", "E", ["B", "D", ["A"]]]; 3const arrB = ["C", "E", ["B", "D", ["A"]]]; 4console.log(JSON.stringify(arrA) == JSON.stringify(arrB)) 5// res: true 6 7// false: BとCの位置が異なっているため 8const arrC = ["C", "E", ["B", "D", ["A"]]]; 9const arrD = ["B", "E", ["C", "D", ["A"]]]; 10console.log(JSON.stringify(arrC) == JSON.stringify(arrD)) 11// res: false 12 13// false: Aが配列になっているかどうかを見ている 14const arrE = ["C", "E", ["B", "D", ["A"]]]; 15const arrF = ["C", "E", ["B", "D", "A"]]; 16console.log(JSON.stringify(arrE) == JSON.stringify(arrF)) 17// res: false

JSON.stringifyを利用すると求めている解を出すことができますが、JSONにして配列が一致しているかどうかを見るだけだとロジックを考える上であまり勉強にはならないため、考え方のロジックについてご教示いただけると幸いです。

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

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

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

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

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

miyabi_takatsuk

2021/01/17 14:17

配列の要素は、文字列のみですか? 数値や、オブジェクトを含む事はありますか? (若干難易度変わる)
nanase21

2021/01/17 14:21

現在の質問では、「文字列」のみで回答の条件は満たせますが、出来れば、「数値や、オブジェクト」を含む形でご教示いただけると幸いです。 なお、「JSON.stringify」を使用しない方法でご教示いただけると嬉しいです。
tanat

2021/01/17 14:34

> なお、「JSON.stringify」を使用しない方法でご教示いただけると嬉しいです。 この条件とその理由を質問に追記して下さい。 要素をシリアライズしてから一致することを確認するのは多くの言語で使用できる汎用的な考え方であり、 JSON.stringifyで出来るのに何を困って質問してるの?となるとともに、JSON.stringifyでは出来ない何か隠された要件がある場合には回答が無駄になってしまいます。
miyabi_takatsuk

2021/01/17 14:40

まず、ご自分でやってみたコードを記載してください。 今のままでは、丸投げになってしまっています。
nanase21

2021/01/17 14:57

質問に質問の意図を追記してみましたが、引き続き考えてみます。
tanat

2021/01/17 14:58

otnさんの回答にある、再帰の概念については把握されていますか? もし把握されていないのであれば `リスト 走査 再帰`あたりで調べてみると、otnさんの回答が理解しやすいかと思います。 次元が不定の多次元データ構造を走査/操作する際によく使われる方法で、言語を問わず使われる概念です(使えない言語もあるとは思いますが)
nanase21

2021/01/17 15:01

@tanatさん 再帰関数というものは知っているのですが使い方について理解できていない状況です...(一旦、otnさんのヒントを元にやってみたいと思います。)
tanat

2021/01/17 15:09

状況と質問意図について把握しました。 補足ありがとうございます。 再帰は取っ付きにくいですが、今回の質問内容には必須かと思います。
nanase21

2021/01/17 15:40

ありがとうございます。 関数内でLoopを回して、値がArrayだったら再帰関数を呼ぶようにして解決できました
tanat

2021/01/17 16:21 編集

(すみません、回答を見逃していたのでコメントを削除します)
guest

回答4

0

ベストアンサー

compareの仕様としては、再帰呼び出しを使って、
・単純な値同士ならそれらが等しいか?
・リスト同士なら
・・長さが等しいか?
・・対応する要素同士全てについてcompareして等しいか?

#追記
これを読んで、そのままコードに出来ないとは思いませんでした。
言語問わないと言うことなので、Arrayかどうかの判断以外はArrayのメソッドは使わず。

JavaScript

1function compare(a, b){ 2 if(Array.isArray(a) && Array.isArray(b)){ 3 if(a.length != b.length) return false; 4 for(let i=0; i<a.length; i++){ 5 if(!compare(a[i],b[i])) return false; 6 } 7 return true; 8 }else{ 9 return a === b; 10 } 11}

投稿2021/01/17 14:29

編集2021/01/17 16:27
otn

総合スコア85901

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

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

nanase21

2021/01/17 15:02

ご教示いただきありがとうございます。 アドバイスを元に試してみます。
guest

0

ロジック

配列の比較方法(ロジックを理解したいだけなので言語は特に問いません)

ロジックを理解したいなら、ロジックを書き出す事から始めてください
(コードを書く必要はありません)

  1. 型が不一致なら、return false
  2. Symbol.toStringTag 値が不一致なら、return false
  3. 対象がPrimitive型かつ値が不一致ならば、return false (NaN 値が存在しうるなら、Object.is())
  4. 対象が配列(Array.isArray())かつ length プロパティ値が不一致ならば、return false
  5. 対象が配列ならば、Array.prototypeforEach または for + hasOwnProperty で走査し、1-4を実行する(length値以下のindex値を持つ要素が全て存在しているならば、for-of を使用しても良い)
  6. 全ての処理が完了したならば、return true

JSON.stringify()

JSON.stringifyを利用すると求めている解を出すことができますが、JSONにして配列が一致しているかどうかを見るだけだとロジックを考える上であまり勉強にはならないため、

JSON.stringify() のロジックは公式文書があります。

Re: nanase21 さん

投稿2021/01/17 15:40

編集2021/01/17 15:45
think49

総合スコア18189

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

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

nanase21

2021/01/17 15:49

ロジックのついての考え方について懇切にご教示いただきありがとうございました。 次回から、コードを書き出す前にロジックを書き出してからコードを考えるようにします。
guest

0

再帰処理を使うといいかと。

javascript

1function compare(a, b){ 2 if ( 3 a !== null && 4 b !== null && 5 (typeof a == 'object' && typeof b == 'object') 6 ) { 7 return Object.entries(a).every(aei => { 8 // entriesは、オブジェクトデータ型をキー別に配列として返すメソッド。配列型も実行可能 9 if (typeof b[aei[0]] == 'undefined') { 10 // bにそもそもキーが存在しなければ、違うのでfalseを返す 11 return false; 12 } else { 13 // オブジェクトの要素が両方配列かオブジェクト、関数の場合、再帰実行 14 if ( 15 aei[1] !== null && 16 b[aei[0]] !== null && 17 ( 18 (typeof aei[1] == 'object' && typeof b[aei[0]] == 'object') || 19 (typeof aei[1] == 'function' && typeof b[aei[0]] == 'function') 20 ) 21 ) { 22 // オブジェクトか関数なので再帰 23 return compare( aei[1], b[aei[0]]); 24 } 25 // プリミティブ値の場合、そのまま比較 26 return aei[1] === b[aei[0]]; 27 } 28 }); 29 } else if (typeof a == 'function' && typeof b == 'function') { 30 // 両者が関数の場合は、単純に関数名を比較(細かくやるのはかなり複雑になる) 31 return a.name == b.name; 32 } 33 34 return a === b; 35} 36 37 38const arrA = ["C", "E", ["B", "D", ["A"]]]; 39const arrB = ["C", "E", ["B", "D", ["A"]]]; 40console.log(compare(arrA, arrB)) 41// res: true 42 43// false: BとCの位置が異なっているため 44const arrC = ["C", "E", ["B", "D", ["A"]]]; 45const arrD = ["B", "E", ["C", "D", ["A"]]]; 46console.log(compare(arrC, arrD)); 47// res: false 48 49// false: Aが配列になっているかどうかを見ている 50const arrE = ["C", "E", ["B", "D", ["A"]]]; 51const arrF = ["C", "E", ["B", "D", "A"]]; 52console.log(compare(arrE, arrF));

一応オブジェクト型には対応してますが、
Map型(厳密には型ではない)などには対応していませんのであしからず。
(もっと処理複雑になります)

追記

関数に関しては、もっと比較せねばならないものが激増するため、関数名が一致するかどうかの比較に留めています。

また、配列はそもそもオブジェクトのため、オブジェクトかどうかを比較し、
再帰させるようにしました。
これにより、オブジェクトの入れ子などにも対応させています。

投稿2021/01/17 15:40

編集2021/01/18 08:14
miyabi_takatsuk

総合スコア9555

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

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

nanase21

2021/01/17 15:48

ご教示いただきありがとうございます。 私の関数と比較しながら勉強させていただきます。
think49

2021/01/17 16:20

- null値でTypeErrorを返す -> compare([null],[{}]); - [undefined] と [] を区別できない - 関数が「プリミティブ値同士なのでそのまま比較」の処理に含まれる(動作上は問題ありませんが、コメントが...) 細かい指摘ですが、null値のTypeErrorが特に気になりました。 typeof演算子には仕様バグがあります。 https://www.262.ecma-international.org/11.0/index.html#sec-typeof-operator https://think49.hatenadiary.org/entry/20120114/1326554107 厳密な話をすれば、typeof演算子の評価値が既定外の文字列("foo" や "bar" など)でもObject型と見なすのが正解ですが、typeof演算子で実装するのは面倒なので、Object() で変換後の値と比較するのがお勧めです。
miyabi_takatsuk

2021/01/17 16:27

ご指摘ありがとうございます! 修正やっていきます。
miyabi_takatsuk

2021/01/18 07:13 編集

think49さん > 修正し、null時のTypeErrorを解消できました。 typeofのバグ、非常に勉強になりました・・・。 ありがとうございます。
guest

0

以下の関数でそれっぽく解決できました(条件3のみfalse返るはずがtrueでなってしまうのですが、一旦回答としては再帰関数を使ってやってみました)

js

1function compare(a, b){ 2 for (let i = 0; i < arr1.length; i++) { 3 if (Array.isArray(arr1[i])) { 4 return compare(arr1[i], arr2[i]) 5 } else if (Array.isArray(arr2[i])) { 6 return compare(arr1[i], arr2[i]) 7 } else if (arr1[i] != arr2[i]) { 8 return false 9 } 10 } 11 return true; 12} 13 14const arrE = ["C", "E", ["B", "D", ["A"]]]; 15const arrF = ["C", "E", ["B", "D", "A"]]; 16console.log(compare(arrE, arrF));

投稿2021/01/17 15:46

nanase21

総合スコア144

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問