

LIST内に設定されているDTOをfor文でkeyに合わせて結合しようとしているのですが、上手いやりかたが思いつきません・・・

やりたいこと：  
array1の中にそれぞれhoge1・hoge2・hoge3を入れ子に持たせたDTOを入れています。keyが一致するレコードを結合しarrayExに設定したいです。  
keyが一致しないものは何もせずにarrayExに設定です。

最終的にarrayExにhoge1・hoge2・hoge3が設定されたものが1件。  
hoge3が設定されただけのkeyが2のものが1件が理想です。

for文をいくつも使って再現はできたのですが、動作が遅いためダメでした・・・

どなたかご教授頂ければ幸いです。

以下ソースです。

[code]

    public class Test {
        public static void main(String[] args) {
            Test1 test1 = new Test1();
            ArrayList<Test1> array1 = new ArrayList<Test1>();
            ArrayList<Test1> array2 = new ArrayList<Test1>();
            ArrayList<Test1> arrayEx = new ArrayList<Test1>();
    
            test1.setKey("1");
            test1.setHoge1("hoge1");
            test1.setHoge2(null);
            test1.setHoge3(null);
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2("hoge2");
            test1.setHoge3(null);
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3("hoge3");
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("2");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3("hoge3");
            array1.add(test1);
            test1 = new Test1();
    
            int count = array1.size();
    
            int i = 0;
            for(i = 0; i < count-1; i++) {
                Test1 A = new Test1();
                Test1 B = new Test1();
                A = array1.get(i);
                B = array1.get(i+1);
    
                if(A.getKey().equals(B.getKey())) {
    
                    if(!(A.getHoge1()==null)) {
                        B.setHoge1(A.getHoge1());
                    }
    
                    if(!(A.getHoge2()==null)) {
                        B.setHoge2(A.getHoge2());
                    }
    
                    if(!(A.getHoge3()==null)) {
                        B.setHoge3(A.getHoge2());
                    }
    
                    arrayEx.add(B);
    
                } else {
                    arrayEx.add(A);
                }
            }
        }
    
    }
    
[/code]

以下現状です・・・色々試しているためかなり修正しています・・・

[code]

    public static void main(String[] args) {
            Test1 test1 = new Test1();
            List<Test1> array1 = new ArrayList<Test1>();
            ArrayList<Test1> array2 = new ArrayList<Test1>();
            List<Test1> arrayEx = new ArrayList<Test1>();
    
            test1.setKey("1");
            test1.setHoge1("hoge1");
            test1.setHoge2(null);
            test1.setHoge3(null);
            test1.setHoge4(null);
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2("hoge2");
            test1.setHoge3(null);
            test1.setHoge4(null);
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3("hoge3");
            test1.setHoge4(null);
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3(null);
            test1.setHoge4("hoge4");
            array1.add(test1);
            test1 = new Test1();
    
    
            test1.setKey("2");
            test1.setHoge1("hoge1");
            test1.setHoge2(null);
            test1.setHoge3(null);
            test1.setHoge4(null);
            array1.add(test1);
            test1 = new Test1();
    
            test1.setKey("2");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3("hoge3");
            test1.setHoge4(null);
            array1.add(test1);
            test1 = new Test1();
    
            int count = array1.size();
    
            int i = 0;
            Iterator<Test1> it = array1.iterator();
    
    
    
            //現在レコード
            Test1 A = new Test1();
            //次レコード
            Test1 B = new Test1();
            //一時退避
            Test1 C = new Test1();
            while(it.hasNext()) {
    
                B = array1.get(i+1);
    
                if(it.hasNext()) {
    
                A = it.next();
                }
                if(!(C.getKey()==null)) {
                    if(B.getKey().equals(C.getKey())) {
                        if(!(B.getHoge1()==null)) {
                            C.setHoge1(B.getHoge1());
                        }
    
                        if(!(B.getHoge2()==null)) {
                            C.setHoge2(B.getHoge2());
                        }
    
                        if(!(B.getHoge3()==null)) {
                            C.setHoge3(B.getHoge3());
                        }
                        if(!(Objects.equals(B.getHoge4(), null))) {
                            C.setHoge4(B.getHoge4());
                        }
                        i = i + 1;
                    }else {
                        arrayEx.add(C);
                        C = new Test1();
                        i = i + 1;
                    }
    
    
    
                } 
    
                if(C.getKey()==null) {
                    if(A.getKey().equals(B.getKey())) {
    
                        if(!(A.getHoge1()==null)) {
                            C.setHoge1(A.getHoge1());
                        }else if(!(B.getHoge1()==null)) {
                            C.setHoge1(B.getHoge1());
                        }
    
                        if(!(A.getHoge2()==null)) {
                            C.setHoge2(A.getHoge2());
                        }else if(!(B.getHoge2()==null)) {
                            C.setHoge2(B.getHoge2());
                        }
    
                        if(!(A.getHoge3()==null)) {
                            C.setHoge3(A.getHoge3());
                        }else if(!(B.getHoge3()==null)) {
                            C.setHoge3(B.getHoge3());
                        }
    
                        if(!(A.getHoge4()==null)) {
                            C.setHoge4(A.getHoge4());
                        }else if(!(B.getHoge4()==null)) {
                            C.setHoge4(B.getHoge4());
                        }
    
                        C.setKey(A.getKey());
    
                        i = i + 1;
    
                    } else {
                        arrayEx.add(B);
                        i = i + 1;
                    }
                }
            }
        }
    
    
[/code]


CC BY-SA 4.0
2020-02-26T14:27:00.923
63384
2020-02-27T11:59:18.907
2020-02-26T16:54:00.557
37980
37980
question
java
LIST内に設定されたDTOの結合処理


同じキーを持つ複数のデータを集約したり集計したりする場合、一般的には Map 型を使うことになるかと思います。

[code]

    import java.util.*;
    
    class Test1{
        private String key;
        private String hoge1;
        private String hoge2;
        private String hoge3;
    
        public void setKey(String newKey){
            this.key = newKey;
        }
        public void setHoge1(String newHoge1){
            this.hoge1 = newHoge1;
        }
        public void setHoge2(String newHoge2){
            this.hoge2 = newHoge2;
        }
        public void setHoge3(String newHoge3){
            this.hoge3 = newHoge3;
        }
        public String getKey(){
            return this.key;
        }
        public String getHoge1(){
            return this.hoge1;
        }
        public String getHoge2(){
            return this.hoge2;
        }
        public String getHoge3(){
            return this.hoge3;
        }
    
        public String toString(){
            return String.format("{key => %s, hoge1 => %s, hoge2 => %s, hoge3 => %s", getKey(), getHoge1(), getHoge2(), getHoge3());
        }
    }
    
    public class Test {
        static ArrayList<Test1> createExampleData(){
            ArrayList<Test1> exampleData = new ArrayList<Test1>();
            Test1 test1;
    
            test1 = new Test1();
            test1.setKey("1");
            test1.setHoge1("1-hoge1");
            test1.setHoge2(null);
            test1.setHoge3(null);
            exampleData.add(test1);
    
            test1 = new Test1();
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2("1-hoge2");
            test1.setHoge3(null);
            exampleData.add(test1);
    
            test1 = new Test1();
            test1.setKey("1");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3("1-hoge3");
            exampleData.add(test1);
    
            test1 = new Test1();
            test1.setKey("2");
            test1.setHoge1(null);
            test1.setHoge2(null);
            test1.setHoge3("2-hoge3");
            exampleData.add(test1);
    
            return exampleData;
        }   
    
        public static void main(String[] args) {
            ArrayList<Test1> array1 = createExampleData();
            ArrayList<Test1> arrayEx = new ArrayList<Test1>();
            TreeMap<String, Test1> tmpTable = new TreeMap<String, Test1>();
            System.out.println("Input array");
    
            for(Test1 test1 : array1) {
                System.out.println(test1);
                String key = test1.getKey();
                if(tmpTable.containsKey(key)){
                    // すでに出現済みのキーの場合 tmpTable から取り出し、そこに結合する
                    Test1 data = tmpTable.get(key);
                    if(test1.getHoge1() != null) {
                        data.setHoge1(test1.getHoge1());
                    }
    
                    if(test1.getHoge2() != null) {
                        data.setHoge2(test1.getHoge2());
                    }
    
                    if(test1.getHoge3() != null) {
                        data.setHoge3(test1.getHoge3());
                    }
                }
                else{
                    // 初出のキーの場合 tmpTable に格納する
                    tmpTable.put(key, test1);
                }
            }
    
            System.out.println("Output array");
            arrayEx.addAll(tmpTable.values());
            for(Test1 test1 : arrayEx) {
                System.out.println(test1);
            }
        }
    }
    
[/code]

以下、実行結果。

[code]

    Input array
    { key => 1, hoge1 => 1-hoge1, hoge2 => null, hoge3 => null }
    { key => 1, hoge1 => null, hoge2 => 1-hoge2, hoge3 => null }
    { key => 1, hoge1 => null, hoge2 => null, hoge3 => 1-hoge3 }
    { key => 2, hoge1 => null, hoge2 => null, hoge3 => 2-hoge3 }
    Output array
    { key => 1, hoge1 => 1-hoge1, hoge2 => 1-hoge2, hoge3 => 1-hoge3 }
    { key => 2, hoge1 => null, hoge2 => null, hoge3 => 2-hoge3 }
    
[/code]


CC BY-SA 4.0
2020-02-27T05:24:42.803
63397
2020-02-27T05:24:42.803
27410
63384
answer


リストに入っているオブジェクトを `key` ごとに分類するのには Stream API の `groupingBy` による `collect`
が利用できます:

[code]

    Map<String, List<Test1>> group = array1.stream().collect(Collectors.groupingBy(Test1::getKey));
    
[/code]

これで `key` ごとに分類された `Test1`
オブジェクトのリストが手に入りましたので、このリスト内の全オブジェクトを"結合"すれば所望の結果が得られます。

"結合"は、同じく Stream API の `reduce` が利用できます:

[code]

    for (List<Test1> list : group.values()) {
        // listの中身はすべて同じkeyでグルーピングされているので
        // 全てを順繰りに結合
        Optional<Test1> merged = list.stream().reduce((t1, t2) -> {
            String t1Hoge1 = t1.getHoge1();
            if (t1Hoge1 != null) {
                t2.setHoge1(t1Hoge1);
            }
            String t1Hoge2 = t1.getHoge2();
            if (t1Hoge2 != null) {
                t2.setHoge2(t1Hoge2);
            }
            String t1Hoge3 = t1.getHoge3();
            if (t1Hoge3 != null) {
                t2.setHoge3(t1Hoge3);
            }
            return t2;
        });
    
        // 結合結果を格納
        merged.ifPresent(arrayEx::add);
    }
    
[/code]

なお、この "結合" は、DTOを扱う上でよく行う処理であり、このような処理を行うためのライブラリも複数開発されています。  
これらのライブラリの(主たる)目的は、いわゆるボイラープレートコードの削減です。

次のページでそのうちのいくつかを見ることができます:

  * [Performance of Java Mapping Frameworks](https://www.baeldung.com/java-performance-mapping-frameworks) \- Baeldung

参考として、MapStructを利用した場合の実装サンプルをリンクします:

  * <https://github.com/yukihane/stackoverflow-qa/tree/master/so63384>


CC BY-SA 4.0
2020-02-27T11:59:18.907
63410
2020-02-27T11:59:18.907
2808
63384
answer