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

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

新規登録して質問してみよう
ただいま回答率
85.30%
HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

Q&A

解決済

2回答

6805閲覧

多次元配列を比較したい

jsrookie

総合スコア24

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

0グッド

2クリップ

投稿2019/08/28 17:22

発生している問題、目指している形

arr0=[["a",1], ["b",2], ["c",3]]
arr1=[["c",3], ["a",1], ["b",2]]
のような2次元配列があるときに、両者の配列は同じと判定するようにしたいです。

arr3=["a", "b", "c"]
arr4=["a", "b", "c"]
のような1次元で中身の順番が同じものではforやJSON等で比較し同じ配列と判定できたのですが、多次元、順不同の場合ではできませんでした。

ご教授お願いします。

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

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

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

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

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

jun68ykt

2019/08/28 17:26

要件を確認させてください。 arr0=[["a",1], ["b",2], ["c",3]] と arr1=[["c",3], ["a",1], ["b",2]] とを等しいと判定させたいことは分かりましたが、 arr0=[["a",1], ["b",2], ["c",3]] と arr2=[[3, "c"], [1, "a"], [2, "b"]] も等しいと判定させたいのでしょうか? つまり、「要素の順番が変わっていてもよい」というルールは、入れ子になっている子のほうの配列にも適用したいのでしょうか?
jsrookie

2019/08/28 17:51

早速のコメントありがとうございます。 > つまり、「要素の順番が変わっていてもよい」というルールは、入れ子になっている子のほうの配列にも適用したいのでしょうか? 今のところは子の方の配列に適用する必要はないと考えています。 つまり、arr0とarr2は違う配列になります。 しかし、同じ配列と判定されても問題はないと考えていますので、jun68ykt様のやりやすい方でお答えいただけると幸いです。 よろしくお願いいたします。
jun68ykt

2019/08/28 18:15

ご回答ありがとうございます。 了解しました。 とりあえず、 > 今のところは子の方の配列に適用する必要はないと考えています。 とのご趣旨に従って、子の配列については、要素の順序が違っていれば異なるものとするという考え方で、回答を書きました。参考になれば幸いです。
guest

回答2

0

数が多くないなら、組み込みのJSON.stringifysortを使うという手もあります。
※数が多いとパフォーマンスとメモリがきついけど・・・

stringifyで中身の配列を文字列に固め、それをソートした配列を作って、さらにその配列をstringifyして比較します。こんな感じ。

javascript

1function check(a, b) { 2 const astr = a.map(v => JSON.stringify(v)).sort(); 3 const bstr = b.map(v => JSON.stringify(v)).sort(); 4 return JSON.stringify(astr) === JSON.stringify(bstr) 5} 6

動くサンプルは以下です。
https://jsbin.com/mezekidigu/edit?js,console,output

注意点は、

  • 内部配列内の順序は無視してます(する場合は、内部配列に対しても要素のstringfyとsortをやる)
  • 内部配列内の型によっては、stringifyで形が変わる可能性がある(Dateとか)ので、型が問題ないか確認する。とりあえずstringnumberしか使ってないなら問題ない。
  • 前述したが、数が多いと遅いとかメモリ使い過ぎとかなる。(stringifyと配列コピー生成のコストが多い)

投稿2019/08/29 01:34

編集2019/08/29 01:37
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

jsrookie

2019/08/30 06:38

回答ありがとうございます。 自分ではできていませんが、私もJSONで挑戦していたのでとても勉強になります。 本当にありがとうございました!
guest

0

ベストアンサー

こんにちは

lodash を使うとうまくやれそうと思ったので、lodash でこのような問題の解を求める質問を探したところ、以下がありました。

これのベストアンサー にある

javascript

1_.isEqual(_.sortBy(array1), _.sortBy(array2))

が使えるのでは思います。以下、そのサンプルです。

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

補足

上記の

_.isEqual(_.sortBy(array1), _.sortBy(array2))

について、 配列array1array2 の要素もまた配列で、その配列の要素は数値だったり文字列だったりと、型が一定していない状況で、_.sortBy の第2引数を与えないときに、どのようなソートになるのかが不明確だったので、少し調べてみましたが、「このようなソートになる」ということを明確に把握することは(今の時点では)できませんでした。

そこで、ランダムな内容の arr0 を作成し、これをシャッフルして arr1 を作り、

_.isEqual(_.sortBy(arr0), _.sortBy(arr1))

が常に true になる(と言ってもさしつかえない)かを試してみました。以下、試してみたコードです。

index.js

javascript

1const _ = require('lodash') 2 3const makeSubArry = () => { 4 const len = _.sample([...Array(16)].map((e, i) => 5 + i)); 5 return [...Array(len)].map(e => { 6 const type = _.sample(['bool', 'int', 'string', 'object']); 7 switch(type) { 8 case 'bool': 9 return _.sample([true, false]); 10 case 'int': 11 return Math.floor(1000.0 * Math.random()) % 100 12 case 'string': 13 return _.sample('abcdefghijklmnopqrstuvwxyz'.split('')) 14 case 'object': 15 return _.sample([ 16 { x: 1, y: 2, z: 3 }, 17 { x: 10, y: 20 }, 18 { x: 11, z: 33 } 19 ]) 20 } 21 }) 22} 23 24const LENGTH = 100; 25 26let equalCount = 0; 27let notEqualCount = 0; 28 29const test = () => { 30 const arr0 = [...Array(LENGTH)].map(makeSubArry); 31 32 for (let i=0; i < 10; i ++ ) { 33 const arr1 = _.shuffle(arr0); 34 const eq = _.isEqual(_.sortBy(arr0), _.sortBy(arr1)); 35 36 if (eq) 37 equalCount ++; 38 else 39 notEqualCount ++; 40 } 41} 42 43for (let i=0; i < 1000; i ++ ) { 44 test(); 45} 46 47console.log(`equalCount: ${equalCount}, notEqualCount: ${notEqualCount}`)

package.json

json

1{ 2 "name": "q208845", 3 "version": "0.0.1", 4 "main": "index.js", 5 "dependencies": { 6 "lodash": "^4.17.15" 7 } 8}

上記のコードでは、以下の内容を一回の試行とし、これを1000回、行います。

  • arr0 を長さ100の配列として作る。
  • arr0 の要素は以下を満たす配列

・長さが、5以上 20以下
・その要素は以下の a)〜 d)のいずれか
a) 真偽値(trueまたはfalse
b) 0以上99以下の整数
c) 小文字のアルファベット1文字から構成される文字列
d) 以下の3つのうちいずれかのオブジェクト
{ x: 1, y: 2, z: 3 }
{ x: 10, y: 20 }
{ x: 11, z: 33 }

  • 上記の arr0 をシャッフルして arr1 を作成する。
  • arr0arr1 に対して

   const eq = _.isEqual(_.sortBy(arr0), _.sortBy(arr1));
を行い、eq の値が true になる回数と、 false になる回数をカウントする。

  • 上記をひとつの arr0 に対して、10回行う。

期待している結果は、true になる回数が 1000 × 10 = 10000、 false になる回数がゼロというものでしたが、何回か実行してみたところ、期待どおりになりました。

投稿2019/08/28 18:12

編集2019/08/29 04:11
jun68ykt

総合スコア9058

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

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

jsrookie

2019/08/30 06:33

前回に引き続き回答ありがとうございます。 海外で質問を探すのは盲点でした。 こんなに簡単にできるとは驚きです。 本当にありがとうございました!
jun68ykt

2019/08/30 09:09 編集

どういたしまして。 > 1次元で中身の順番が同じものではforやJSON等で比較し同じ配列と判定できた ということで、まず最も簡単なものについて、自作して作ることができたので、次に、 > 多次元、順不同 の比較に発展させようという試みは、大変よいと思います。ただ、 > 1次元で中身の順番が同じもの の比較が出来てからの次のステップとして、"多次元かつ順不同" にいっぺんに行くのは、ちょっと欲張り過ぎたのかもしれません。(欲張りたい気持ちも分からなくはないのですけれども。) なので、次は  1) 1次元のまま順不同での比較 と  2) 順番は同じ比較で2次元 とを別々にやってみて、その後、1) かつ 2) すなわち、今回のご質問の課題をやってみるとよいかもしれません。(もうすでに 1) と 2) は出来ており楽勝だった、ということでしたらすみません) さらに 2) の発展で、  3) 順番は同じで n 次元 というのも挑戦しがいがあると思います。これらをやってくときに、配列の要素としては、とりあえずオブジェクトは除外するとよいでしょう。オブジェクトの比較が入ってくると途端に面倒になってきます。 2つの配列の内容が等しいかの判定、あるいは、2つのオブジェクトの内容が等しいとか判定するというコードを最も単純なところから初めて、徐々に汎用的にしていく作業を一度でも自作してみると、「何が来ても大丈夫」なものを作るのがいかに大変か分かります。そうすると「かなわぬ時の lodash 様頼み」ということになってきますので、lodash のドキュメント https://lodash.com/docs についても一度上から下まで、どんなメソッドがあるかざっと見ておくとよいかもしれません。 英語を正確に和訳しながら読めなくてもいいです。 逆にサンプルコードを読めば、どういうことをしてくれるメソッドかは大体分かるので、そこから逆に、 「こういうことをやることを、英語では ○○○というのか」 という感じで、メソッドによる効果と英語がつながってきて、すばやく有用な情報にたどりつける検索キーワードでググれるようになってきます。 今回のご質問の課題だと lodash compare two arrays といったキーワードでGoogle検索すると、キーワードが適切なら、Stackoverflow の投稿がヒットします。(今回の回答員挙げた Stackoverflow の投稿も検索結果上位に出てくると思います。)その中で、多くのGood がついている回答をありがたく拝借しましょう。 まとめますと ・ある程度のところまでは自分で書ける。(これは前提) ・楽勝で書けたコードを踏み台にして、さらに汎用的なものを自作しようとして大変だった。  どこがどう大変になるかも分かった。 ・その上で lodash のような便利なものを使いこなせる。 というのが望ましいかと思います。 上記3点目の「使いこなす」とは、どんなメソッドがあるかを暗記するのではなく、自分のやりたいことを端的に表す英文を作るか、英文になっていなくても、英単語を並べてググって、有用な情報に素早くたどり着いて、そこに書いてあることを自分の課題に適用できる、というような意味です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問