前提・実現したいこと
Java初心者です。
二つのList<Map<String,Object>>型で作成したListの要素を比較し
異なる要素があるListのみ(下記ソースコードでいうと[1]のみ)を条件分岐させたいです。
ご教示いただければと思います。
発生している問題・エラーメッセージ
① 下記の書き方だと ListA[0]とListB[0] ListA[0]とListB[1] ListA[1]とListB[0] ListA[1]とListB[1] の比較をしているようです。 【やりたいこと】 ListA[0]とListB[0] ListA[1]とListB[1] のみ比較して、条件分岐させたいと考えています 格納が多くなるにつれて ListA[3]とListB[3] ListA[4]とListB[4] .... ② ListAをListBとしてコピーしたのですが、 ListAの要素を書き換えるとListBも更新されます。(意図しない実装になっています。) サイト等を見てディープコピーとしてコーディングしているのですが、なぜこうなるのかが分かりません。
該当のソースコード【OLD】
java
1List<Map<String,Object>> ListA new ArrayList<Map<String,Object>>(); 2 3Map<String,Object> mapA = new HashMap<String,Object>(); 4Map<String,Object> mapB = new HashMap<String,Object>(); 5 6// ListAに格納処理 7mapA.put ("性別", "男性"); 8mapA.put ("名前", "山田"); 9mapA.put ("年齢", "20"); 10ListA.add(mapA) 11 12mapB.put ("性別", "女性"); 13mapB.put ("名前", "田中"); 14mapB.put ("年齢", "25"); 15ListA.add(mapB) 16 17// ListBに格納処理(ListAの[1]の年齢だけ異なる) 18List<Map<String,Object>> ListB new ArrayList<Map<String,Object>>(); 19mapA.put ("性別", "男性"); 20mapA.put ("名前", "山田"); 21mapA.put ("年齢", "20"); 22ListB.add(mapA) 23 24mapB.put ("性別", "女性"); 25mapB.put ("名前", "田中"); 26mapB.put ("年齢", "50"); 27ListB.add(mapB) 28 29//Listを比較し、異なるものを条件分岐させる 30for(Map<String, Object> map : ListA) { 31 for(Map<String, Object> map2 : ListB) { 32 if(!(map.equals(map2))) { 33 34//DB更新処理 35 } 36 } 37 }
修正後のソースコード
java
1List<Map<String, Object>> ListA = new ArrayList<Map<String, Object>>(); 2 3Map<String, Object> mapA = new HashMap<String, Object>(); 4Map<String, Object> mapB = new HashMap<String, Object>(); 5 6// ListAに格納処理 7mapA.put("性別", "男性"); 8mapA.put("名前", "山田"); 9mapA.put("年齢", "20"); 10ListA.add(mapA); 11 12mapB.put("性別", "女性"); 13mapB.put("名前", "田中"); 14mapB.put("年齢", "25"); 15ListA.add(mapB); 16 17// リストAを複製 18List<Map<String, Object>> ListB = new ArrayList<Map<String, Object>>(ListA); 19 20//間違った実装によりコメントアウト 21//mapB.put("性別", "女性"); 22//mapB.put("名前", "田中"); 23mapB.put("年齢", "50"); 24//ListA.add(mapB); 25 26 27// ListAとListBを比較し、異なるものを条件分岐させる 28for (Map<String, Object> map1 : ListA) { 29 for (Map<String, Object> map2 : ListB) { 30 if (!(map1.equals(map2))) { 31 32 // DB更新処理 33 } 34 } 35}
試したこと
java
1Map<String, Object> mapCompare = new HashMap<String, Object>(); 2Map<String, Object> motoMap = new HashMap<String, Object>(); 3 4for (int j = 0; j < ListA.size(); j++) { 5 motoMap.putAll(ListA.get(j)); 6 for (int i = 0; i < ListB.size(); i++) { 7 mapCompare.putAll(ListB.get(i)); 8 if (!(motoMap.equals(mapCompare))) { 9 } 10 } 11}
補足情報(FW/ツールのバージョンなど)
> 下記の書き方だと
...
> の比較をしているようです。
「しているよう」、と言いますか、それは質問さん自身が2重ループでまさにそのように比較しているからなのですが。LstA[0]とListB[0], ListA[1]とListB[1] のように比較したいのであれば、ループはひとつで良いはずです。
また、要素であるmap同士を比較する方法、if(!(map.equals(map2))) の部分はそれとは分けて考えましょう。
> 格納する要素が多くなるほど処理が多くなりそうなため採用しませんでいた。
多くなっても要望が実現できるなら、まず自分なりにそれをやってみるべきです。
[質問するときのヒント] https://teratail.com/help/question-tips
該当ソースコードの map.equals(map2) は false になる想定でしょうか。現状だと true になると思いますが、認識は合っていますか。
例えば、1回目のループにおける map, map2 は両者とも mapA を参照しています。同じ参照同士の比較は true になると思います。
ソースコードを見るとあたかも ListA には3つの要素が入った mapA, mapB を、ListB には6つの要素が入った mapA, mapB を add したいように見えたので、もしそうだとしたら意図していない実装になっているのではないかと推測しています。
;がなかったりでこのソースコードではコンパイルが通りません
大前提としてコンパイルが通るようにまずはしてください
勘違いされている点が幾つかあるようですが、まず for ループをする直前で、ListA/B 両方の中のデータを表示してみて、思ったようになっているか確認しては如何でしょうか。
回答遅くなり申し訳ございません。
また、アドバイスありがとうございます。
Crimson_Tide様がおっしゃるように
まずはコンパイルが通るように修正しました。
BluOxy様、jimbe様がおっしゃるように
修正前のコードを動かして確認すると意図しない実装になっていました。
そこで私が実装してかったのは、
更新前のListAをコピーしそれを保持した状態で(ListBとして)
ListAの要素を更新したあとに、ListAとListBを比較して条件分岐させる。です。
ただ、それを実装したときにまた新たに問題が発生しました。
【発生している問題・エラーメッセージの②】
dodox86様がおっしゃるように
試してみたことを書きました。
ただ、結局結果は同じでした。
>LstA[0]とListB[0], ListA[1]とListB[1] のように比較したいのであれば、ループはひとつで良いはずです。また、要素であるmap同士を比較する方法、if(!(map.equals(map2))) の部分はそれとは分けて考えましょう。
この部分がどうしても考えられず(サイトを見てもListを二重ループしてる方法しか探すことができず)
ListAとListBの比較がうまくいできませんでした。
ご回答内容分かりずらくて、申し訳ございませんがご教示いただければ助かります。
コード修正の対応ありがとうございます。
できれば、import文、class文、mainメソッド文も省略せず掲載して頂いたほうが、回答しようとする人がコードをそのまま利用し確認しやすいかと思います。
比較処理の前に今一度比較するデータ(ListAとListBの中身)が想定通りか確認してみてください。
IDEのデバッグ機能を使ってもいいですし、例えば2重のfor文の前に以下のように追記して実行してみてもいいかと思います。
System.out.println("ListA:" + ListA.get(1).get("年齢") + " 要素数:" + ListA.size());
System.out.println("ListB:" + ListB.get(1).get("年齢") + " 要素数:" + ListB.size());
ListAとListBは、それぞれ二つのMAPインスタンスを保持し、2つめマップインスタンスの年齢をキーとした値がListAとListBでは異なっている(25と50)状態を想定している、と私は受け取ったのですが違うでしょうか?
> この部分がどうしても考えられず(サイトを見てもListを二重ループしてる方法しか探すことができず)
「どうしても」に対して「どうして」考えられないのかを考えてください。
プログラミングは「自分で正解を設定して組み立てるパズル」です。サイトの情報はその著者自身の正解に対する答えに過ぎず、 THE_GUTS さんの正解と同じとは限りません。
サイトからコードを得るということは、そのコードが意味するものを知るということです。コードをコピペして動かないという状況は、意味するものを知れていないと思われます。知れていないのは、コードの個々の要素、ループによる各変数の変化やそれによる比較対象の指定のされ方、比較自体の方法等のどこか、あるいは全てに知識・理解の不足があるのではないでしょうか。
それを見出して解決しなければ、ただ弄り回すか、丸投げになるでしょう。
Crimson_Tide様
アドバイスありがとうございます。
import文、class文、mainメソッド文の省略の件、後ほど記載します。
修正後のソースコードにてSystem.out.printlnで確認すると
ListA:50 要素数:3
ListB:50 要素数:2
でした。
これは実装したいものとは異なります。
>ListAとListBは、それぞれ二つのMAPインスタンスを保持し、2つめマップインスタンスの年齢をキーとした値がListAとListBでは異なっている(25と50)状態を想定している、と私は受け取ったのですが違うでしょうか?
はい、そうです。
ListA:25 要素数:2
ListB:50 要素数:2
が想定している結果となります。
jimbe様
おっしゃる通りだと思います。
まだ知識が浅いので、サイト等を参考にしながら作成していますが、知識理解の不足があるのだと思います。
List同士の比較もう少し動かしながら調べてみます。
リスト全体、リスト同士の比較もそうですが、
> if (!(map1.equals(map2))) {
のような単にMapのオブジェクト同士のequals()メソッドを利用した比較で、想定した比較の結果を得られているか疑問です。「修正後のソースコード」とか「試したこと」で示されたコードも、正直、理解されているように思えない成り行きです。あれもこれも同時に一緒にやるのではなく、ひとつひとつ確実にしてから進めてはどうでしょう。現時点の質問者さんにはちょっと難しすぎる問題のように思えますが、急がなければならない何かの課題なのでしょうか。ググることを否定はしませんが、基本ができていない状態で、あちこちのサイトを見るのは振り回されるばかりだし、断片的に使えそうなコードを持ってきて完成させようとするのは無謀です。
回答1件
あなたの回答
tips
プレビュー