Java 8 Streams - как объединить элементы из списка с одинаковыми полями в один элемент и суммировать - PullRequest
0 голосов
/ 18 октября 2018

У меня один вопрос - у меня есть список элементов A:

class A {
String fieldA;
int fieldB
}

Я хотел бы объединить все элементы с одним и тем же полем A в один элемент с суммированием всех значений из fieldB следующим образом:

el1 = AAA 5
el2 = AAA 7
el3 = AAA 2

Результат:

one element: AAA 14

Как я могу сделать это, используя потоки Java 8?

Таким образом, в конце моего списка должно быть меньше элементов, чем в начале,Мне нужно найти все элементы с одинаковым полем A и объединить их в один элемент с суммированным полем B.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 18 октября 2018

Йо может сделать что-то подобное, если ваш класс изменчив.

List<A> out = list.stream()
    .collect(Collectors
        .collectingAndThen(
            Collectors.toMap(ele -> ele.getFieldA(), Function.identity(), (a, b) -> {
              a.setFieldB(a.getFieldB() + b.getFieldB());
              return a;
            }), m -> new ArrayList<>(m.values())));

В этом случае вы сначала создадите карту типа

Map<fieldA, A> 

, имеющую A (объект)) значение fieldB как сумма всех значений fieldB соответствующего значения fieldA, а затем просто преобразование набора значений Map в список.

Надеюсь, это поможет.

0 голосов
/ 18 октября 2018

Я знаю, что вы попросили способ сделать это с помощью потоков.Другие ответы показывают этот подход.Здесь, для полноты, я показываю другой способ:

Map<String, A> map = new LinkedHashMap<>();
yourListOfAs.forEach(a -> map.merge(a.getFieldA(), new A(a), A::merge));

Collection<A> reduced = map.values(); // or new ArrayList<>(map.values())

Для этого требуется конструктор копирования и метод merge в классе A:

public A(A copy) {
    this.fieldA = copy.fieldA;
    this.fieldB = copy.fieldB;
}

public A merge(A another) {
    this.fieldB += another.fieldB;
    return this;
}
0 голосов
/ 18 октября 2018

Вы можете сделать это так,

List<A> reducedAList = aList.stream()
    .collect(Collectors.groupingBy(A::getFieldA, Collectors.summingInt(A::getFieldB)))
    .entrySet().stream()
    .map(e -> new A(e.getKey(), e.getValue()))
    .collect(Collectors.toList());

Вместо того, чтобы заменить существующий List<A>, давайте создадим новый список с уменьшенными значениями A.Для этого сначала создайте map, считая значение fieldA в качестве ключа и сумму значений fieldB с тем же ключом, что и значение.Затем выполните итерацию набора записей карты и создайте новый экземпляр A из каждой записи и соберите его в контейнер.Это то, что нам нужно.

...