Java Streams. Как объединить и объединить список нескольких объектов в один объект? - PullRequest
0 голосов
/ 15 мая 2019

У меня есть требование, связанное с потоками в Java. Мне нужно перебрать список объектов, где каждый объект имеет свойство Integer и свойство List.

Что мне нужно, так это то, что если одни и те же объекты имеют одинаковый идентификатор, мне нужно составить списки. Позвольте мне проиллюстрировать пример с небольшим количеством простого кода:

Вот только определение 2 простых классов:

public static class Wrapper {
  Integer id ;
  List<Element> list;

  public Wrapper(Integer id, List<Element> list) {
    this.id = id;
    this.list = list;
  } 
}

public static class Element {
  String content ;

   public Element(String content) {
       this.content = content;
   } 
 }

Теперь в методе Main Java создаем те же объекты для части примера:

    List<Wrapper> list=new ArrayList();
    ArrayList<Element> listForWrapper1= new ArrayList();
    listForWrapper1.add(new Element("Content A"));
    listForWrapper1.add(new Element("Content B"));

    ArrayList<Element> listForWrapper2= new ArrayList();
    listForWrapper2.add(new Element("Content C"));
    listForWrapper2.add(new Element("Content D"));

    ArrayList<Element> listForWrapper3= new ArrayList();
    listForWrapper3.add(new Element("Content E"));
    listForWrapper3.add(new Element("Content F"));

     Wrapper wrapper1=new Wrapper(1,listForWrapper1);
     Wrapper wrapper2=new Wrapper(2,listForWrapper2);
     //Here this Wrapper has the same ID than wrapper2
     Wrapper wrapper3=new Wrapper(2,listForWrapper3);


     //Adding Elements to List
     list.add(wrapper1);
     list.add(wrapper2);
     list.add(wrapper3);

Как видите, я добавляю в список 3 Обёртки, НО 2 из них имеют одинаковый идентификатор

Я хочу, чтобы идентификаторы Wrapper были одинаковыми в массиве, просто объедините оба списка. Таким образом, в этом примере результат должен быть:

Список с 2 элементами :

Элемент 1 : объект-обертка с идентификатором 1, с 2 элементами внутри его свойства списка, содержимого элемента A и содержимого элемента B

Элемент 2 : объект-оболочка с идентификатором 2, с 4 элементами внутри его свойства списка, содержимым элемента C, содержимым элемента D, содержимым элемента E и содержимым элемента F.

Как мне достичь этого результата с помощью Streams? Не могу придумать ни одного элегантного решения!

Заранее спасибо!

List<Wrapper> combinedList=list.stream().....

Ответы [ 3 ]

2 голосов
/ 15 мая 2019

Вы можете использовать BinaryOperator<U> mergeFunction в Collectors.toMap`.

Collection<Wrapper> wrapperList = wrappers.stream()
        .collect(Collectors.toMap(Wrapper::getId, x -> x),
                (oldVal, newVal) -> {
                    oldVal.getElements().addAll(newVal.getElements());
                    return oldVal;
                }))
        .values();

В приведенном выше коде я написал mergeFunction, чтобы всегда возвращать oldVal (oldVal, newVal) -> oldVal, но вы можете изменить то, что вы хотите.Лямбда-функция x -> x также может быть записана как Function.identity().

1 голос
/ 15 мая 2019

Вы можете использовать Collectors.toMap() для добавления значений карты с помощью функции слияния.

Map<Integer, Wrapper> collect = 
        list.stream()
            .collect(Collectors.toMap(w -> w.id,
                                      w -> w,
                                      (w1, w2) -> {
                                         w1.list.addAll(w2.list);
                                         return w1;
                                      })
            );

Рабочая

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Wrapper> list=new ArrayList();
        ArrayList<Element> listForWrapper1= new ArrayList();
        listForWrapper1.add(new Element("Content A"));
        listForWrapper1.add(new Element("Content B"));

        ArrayList<Element> listForWrapper2= new ArrayList();
        listForWrapper2.add(new Element("Content C"));
        listForWrapper2.add(new Element("Content D"));

        ArrayList<Element> listForWrapper3= new ArrayList();
        listForWrapper3.add(new Element("Content E"));
        listForWrapper3.add(new Element("Content F"));

        Wrapper wrapper1=new Wrapper(1,listForWrapper1);
        Wrapper wrapper2=new Wrapper(2,listForWrapper2);
        //Here this Wrapper has the same ID than wrapper2
        Wrapper wrapper3=new Wrapper(2,listForWrapper3);


        //Adding Elements to List
        list.add(wrapper1);
        list.add(wrapper2);
        list.add(wrapper3);

Map<Integer, Wrapper> collect =
        list.stream()
            .collect(Collectors.toMap(w -> w.id,
                                      w -> w,
                                      (w1, w2) -> {
                                         w1.list.addAll(w2.list);
                                         return w1;
                                      })
            );
        System.out.println( collect.values() );
    }
}

 class Wrapper {
    Integer id ;
    List<Element> list;

    public Wrapper(Integer id, List<Element> list) {
        this.id = id;
        this.list = list;
    }

     @Override
     public String toString() {
         return id + ":" + list;
     }
 }

 class Element {
    String content ;

    public Element(String content) {
        this.content = content;
    }

     @Override
     public String toString() {
         return content;
     }
 }

выход

[1:[Content A, Content B], 2:[Content C, Content D, Content E, Content F]]
0 голосов
/ 15 мая 2019

Вы можете попробовать это:

Map<Integer, Wrapper> map = list.stream().collect(Collectors.toMap(wrapper -> wrapper.id /*Use the ids as the keys*/, wrapper -> wrapper /*Return the same wrapper as the value*/, (w1, w2) -> {
         w1.list.addAll(w2.list); // If a wrapper with the same id is found, then merge the list of wrapper 2 to the list of wrapper 1 and return wrapper 1.
         return w1;
     }));

list = new ArrayList<>(map.values()); // Create new ArrayList with the values of the map.



System.out.println(list); // [cci.Test$Wrapper@4eec7777, cci.Test$Wrapper@3b07d329]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...