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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

ArrayList

Java用のタグです。arrayListはListインターフェースを実装した、リサイズ可能な配列用クラスです。

Q&A

解決済

1回答

640閲覧

2つのMapを要素とするList型を比較して、異なる値だけを抽出したい

fgjdnsk

総合スコア2

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

ArrayList

Java用のタグです。arrayListはListインターフェースを実装した、リサイズ可能な配列用クラスです。

0グッド

0クリップ

投稿2023/08/21 07:54

編集2023/08/22 13:14

Java初心者です。
お手柔らかにお願いいたします。

実現したいこと

Mapを要素とするList型(List<Map<String,String>>)が2つあり、mapList1とmapList2とします。
中身のデータは、例)のような形になっており、mapList1とmapList2の値をそれぞれ比較して、異なる値だけを別のMapを要素とするList型(「diffValueMapList」とします。)に格納したいです。
比較する際には、mapList1のListの要素単位で、Keyの値が等しいvalueを比較したいです。
以下の例を元にすると、mapList1のList[0]とmapList2のList[0]の中身を比較するのであり、mapList1のList[0]とmapList2のList[1]の中身を比較することはないということです。
diffValueMapListに格納する際は、List[0]の中に、mapList1の値とmapList2の値を格納したいです。

例)
■mapList1
List[0]
-Map(Key=キー①,value=1111)
-Map(Key=キー②,value="あああ")

List[1]
-Map(Key=キー①,value=2222)
-Map(Key=キー②,value="いいい")

List[2]
-Map(Key=キー①,value=2222)
-Map(Key=キー②,value="ううう")

■mapList2
List[0]
-Map(Key=キー①,value=1111)
-Map(Key=キー②,value="かかか")

List[1]
-Map(Key=キー①,value=2222)
-Map(Key=キー②,value="いいい")

List[2]
-Map(Key=キー①,value=2222)
-Map(Key=キー②,value="くくく")

以下のように格納したい
■diffValueMapList
List[0]
-Map(Key=キー②,value="あああ")
-Map(Key=キー②,value="かかか")
List[1]
-Map(Key=キー②,value="ううう")
-Map(Key=キー②,value="くくく")

前提

特にないです。

発生している問題・エラーメッセージ

diffValueMapList1に格納されるデータが想定より少ない。
以下のソースコードで、最終的にはdiffValueMapList1とdiffValueMapList2をまとめた形で戻り値としたかったのですが、diffValueMapList1が想定通りにならなかったため、コードは途中の状態となっております。

該当のソースコード

冗長なコードになっていると思いますが、効率よく比較できるように修正できそうであれば教えて頂きたいです。

Java

1 public List<Map<String, String>> checkMapList(List<Map<String, String>> mapList1, List<Map<String, String>> mapList2){ 2 Map<String,String> diffValueMap1 = new HashMap<>(); 3 Map<String,String> diffValueMap2 = new HashMap<>(); 4 5 List<Map<String, String>> diffValueMapList1 = new ArrayList<>(); 6 List<Map<String, String>> diffValueMapList2 = new ArrayList<>(); 7 8 for(Map<String,String> resultMap11:mapList1){ 9 for(Map.Entry<String, String> resultValue11:resultMap11.entrySet()) { 10 boolean isEqual1 = false; 11 for (Map<String, String> resultMap12 : mapList2) { 12 for (Map.Entry<String, String> resultValue12 : resultMap12.entrySet()) { 13 if(resultValue11.getValue().equals(resultValue12.getValue())) { 14 isEqual1 = true; 15 break; 16 } 17 } 18 } 19 if(isEqual1 == false){ 20 diffValueMap1.put(resultValue11.getKey(),resultValue11.getValue()); 21 diffValueMapList1.add(diffValueMap1); 22 } 23 } 24 } 25 26 for(Map<String,String> resultMap21:mapList2){ 27 for(Map.Entry<String,String> resultValue21:resultMap21.entrySet()){ 28 boolean isEqual2 = false; 29 for(Map<String,String> resultMap22:mapList1){ 30 for(Map.Entry<String,String> resultValue22:resultMap22.entrySet()){ 31 if(resultValue22.getValue().equals(resultValue21.getValue())){ 32 isEqual2 = true; 33 break; 34 } 35 } 36 } 37 if(isEqual2 == false){ 38 diffValueMap2.put(resultValue21.getKey(),resultValue21.getValue()); 39 diffValueMapList2.add(diffValueMap2); 40 } 41 } 42 } 43 return diffValueMapList1; 44 } 45

試したこと

試行錯誤した結果、自分の求める形に一番近い結果となったのが上記コードでした。

補足情報(FW/ツールのバージョンなど)

特にないです。

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

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

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

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

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

momon-ga

2023/08/21 09:14

>以下のように格納したい ■diffValueMapList List[0] -Map(Key=キー②,value="あああ") -Map(Key=キー②,value="かかか") public List<Map<String, String>> checkMapListでは、 そもそもデータ構造的に不可能です。 diffValueMapList.get(0).get("キー②")で、"あああ"と"かかか"の2種類を取得できません >自分の求める形に一番近い結果 あと勝ちで同一キーで値が上書きされてるはずです
fgjdnsk

2023/08/21 09:51

>diffValueMapList.get(0).get("キー②")で、"あああ"と"かかか"の2種類を取得できません おっしゃる通りです。 List<Map<String,String>>ではなく、List<List<String>>の型だと格納方法について実現できないでしょうか。 for文の入れ子になった場合の異なる値だけを抽出するロジックがわからないため、ご教示いただけますと幸いです。
jimbe

2023/08/21 11:45 編集

> ~だと格納方法について実現できないでしょうか。 コードが動いているなら、実際にその例の値で動作させればどうなるのか分かるはずです。 List<List<String>> でどうやってキーと値のペアを持たせるつもりでしょうか。 反射的に答えを求めるのではなく、どのような時にどうなってしまうのか等をある程度は想定して考えてみてください。 >効率よく比較できるように修正できそうであれば 結果が正しくない状態で効率を求めるのは早すぎです。
fgjdnsk

2023/08/21 11:53

> List<List<String>> でどうやってキーと値のペアを持たせるつもりでしょうか。 深く考えずにコメントしてしまいました。申し訳ありません。 自分が思いつく範囲だと、List<Map<String,List<String>>>で、一つのKeyに対して複数のValueを持たせるような形にするのが良いように思いました。 > コードが動いているなら、実際にその例の値で動作させればどうなるのか分かるはずです。 デバッグ実行で確認しておりますが、for文の入れ子になっているアルゴリズムが苦手で上手くいかなかったため、こちらで質問させていただいております。 > 結果が正しくない状態で効率を求めるのは早すぎです。 おっしゃる通りです。 綺麗なコードでなくてもいいからと、試した結果が本文に記載のコードです、、。
jimbe

2023/08/21 12:00

質問に書かれている例だけを見れば、例えば mapList1 と mapList2 は必ず size() は同じなのでしょうか。 また、確かにコードの入れ子が酷く何をやっているのか分かり難いのですが、 map に入っているキーは必ず同じとは限らず、一方だけにあるキー(と値)は比較するまでも無く違いとして結果に出すのでしょうか。
guest

回答1

0

ベストアンサー

おそらく質問から簡単には読み取れない条件があると思いますが、例は動きます。

java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) { 5 List<Map<String,String>> list1 = List.of( 6 Map.of("キー①", "1111", "キー②", "あああ"), 7 Map.of("キー①", "2222", "キー②", "いいい"), 8 Map.of("キー①", "2222", "キー②", "ううう") 9 ); 10 List<Map<String,String>> list2 = List.of( 11 Map.of("キー①", "1111", "キー②", "かかか"), 12 Map.of("キー①", "2222", "キー②", "いいい"), 13 Map.of("キー①", "2222", "キー②", "くくく") 14 ); 15 16 List<Map<String,List<String>>> result = diff(list1, list2); 17 18 System.out.println(result); 19 } 20 21 private static List<Map<String,List<String>>> diff(List<Map<String,String>> list1, List<Map<String,String>> list2){ 22 List<Map<String,List<String>>> result = new ArrayList<>(); 23 24 for(int i=0; i<Math.max(list1.size(), list2.size()); i++) { 25 Map<String,String> map1 = i < list1.size() ? list1.get(i) : Collections.emptyMap(); 26 Map<String,String> map2 = i < list2.size() ? list2.get(i) : Collections.emptyMap(); 27 28 Set<String> keys = new HashSet<>(map1.keySet()); 29 keys.addAll(map2.keySet()); //両方の全てのキー 30 31 Map<String,List<String>> map = new HashMap<>(); 32 for(String key : keys) { 33 if(!Objects.equals(map1.get(key), map2.get(key))) { 34 List<String> list = new ArrayList<>(); 35 if(map1.containsKey(key)) list.add(map1.get(key)); 36 if(map2.containsKey(key)) list.add(map2.get(key)); 37 map.put(key, list); 38 } 39 } 40 41 if(!map.isEmpty()) result.add(map); 42 } 43 44 return result; 45 } 46}
[{キー②=[あああ, かかか]}, {キー②=[ううう, くくく]}]

よく見ると、差分を求める処理ではマップ内のキーや値は String であるかどうかは関係ありません。
ですのでジェネリクスを用いることで型の縛りを無くすことが出来、またタイピング量を減らすことにもなります。(main は上のままで使えます。)
list の比較処理内で map の比較処理を呼ぶ形にすることで、いつ何に対して処理を行うのかが明白になります。

java

1 private static <K,V> List<Map<K,List<V>>> diff(List<Map<K,V>> list1, List<Map<K,V>> list2) { 2 List<Map<K,List<V>>> result = new ArrayList<>(); 3 4 for(int i=0; i<Math.max(list1.size(), list2.size()); i++) { 5 Map<K,List<V>> map = diff(getOrEmpty(list1,i), getOrEmpty(list2,i)); 6 if(!map.isEmpty()) result.add(map); 7 } 8 9 return result; 10 } 11 //list の i 番目の map を返す. i 番目が無い場合は空の map を返す. 12 private static <K,V> Map<K,V> getOrEmpty(List<Map<K,V>> list, int i) { 13 return i < list.size() ? list.get(i) : Collections.emptyMap(); 14 } 15 //Map の diff 16 private static <K,V> Map<K,List<V>> diff(Map<K,V> map1, Map<K,V> map2) { 17 Map<K,List<V>> result = new HashMap<>(); 18 19 Set<K> keys = new HashSet<>(map1.keySet()); 20 keys.addAll(map2.keySet()); //両方の全てのキー 21 22 for(K key : keys) { 23 if(Objects.equals(map1.get(key), map2.get(key))) continue; 24 25 List<V> list = new ArrayList<>(); 26 if(map1.containsKey(key)) list.add(map1.get(key)); 27 if(map2.containsKey(key)) list.add(map2.get(key)); 28 result.put(key, list); 29 } 30 return result; 31 }

投稿2023/08/21 12:12

編集2023/08/22 04:14
jimbe

総合スコア12492

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

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

fgjdnsk

2023/08/21 15:12

ご回答いただき、誠にありがとうございます。 自分の環境で試したところ、求めていた値を取得することが出来ました。 自分では思いつかないようなロジックでしたので、jimbeさんのコードを見て勉強させていただきます。 細かい条件等、記載が足りていない部分があり申し訳なかったです。 本当にありがとうございます!
jimbe

2023/08/21 19:08 編集

質問コードが複雑になった原因は、 >mapList1のList[0]とmapList2のList[0]の中身を比較するのであり、mapList1のList[0]とmapList2のList[1]の中身を比較することはない と仰っているにも関わらず二つのリストを二つの (拡張) for で全組み合わせを処理する形にしてしまった >for(Map<String,String> resultMap11:mapList1){ > for (Map<String, String> resultMap12 : mapList2) { こと(『mapList1のList[0]とmapList2のList[1]の中身を比較することはない』をやってしまっている)や、 map を list のように entrySet で全要素をループで処理しようとした >for(Map.Entry<String, String> resultValue11:resultMap11.entrySet()) { ことでしょう。(拡張 for を使ってみたかったかのような乱立状態です。) その為 map1 に無くて map2 にあるキーを処理する為に全体を二つ並べることになっています。 比較するマップは、先の通り(回答コード 24~26 行目のように)同じインデックス(i)の要素を取り出すだけで決まるはずですし、二つのマップのキーの 和集合 を作りそれを元に処理することで、一方を主にして従を調べ主従逆転させてまた調べるようなことは不要になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.53%

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

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

質問する

関連した質問