Эффективный способ группировки по заданному списку на основе ключа и собрать в тот же список Java 8 - PullRequest
0 голосов
/ 27 августа 2018

У меня есть следующий класс:

class A{
  String property1;
  String property2;
  Double property3;
  Double property4;
}

Таким образом, свойство1 и свойство2 - это ключ.

class Key{
      String property1;
      String property2; 
}

У меня уже есть список A, как показано ниже:

List<A> list=new ArrayList<>();

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

Function<A, Key> keyFunction= r-> Key.valueOf(r.getProperty1(), r.getProperty2());

Но тогда, когда я делаю группу, я должен взять сумму свойства3 и среднее значение свойства 4.

Мне нужен эффективный способ сделать это.

Примечание : я пропустил методы данных классов.

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Попробуй так:

 Map<A,List<A>> map = aList
                     .stream()
                     .collect(Collectors
                             .groupingBy(item->new A(item.property1,item.property2)));

List<A> result= map.entrySet().stream()
            .map(list->new A(list.getValue().get(0).property1,list.getValue().get(0).property1)
                    .avgProperty4(list.getValue())
                    .sumProperty3(list.getValue()))
            .collect(Collectors.toList());

и создайте avgProperty4 и sumProperty3 методы, подобные этому

public A sumProperty3(List<A> a){
  this.property3 = a.stream().mapToDouble(A::getProperty3).sum();
  return this;
}

public A avgProperty4(List<A> a){
   this.property4 =  a.stream().mapToDouble(A::getProperty4).average().getAsDouble();
   return this;
}

result = aList.stream().collect(Collectors
            .groupingBy(item -> new A(item.property1, item.property2),
                    Collectors.collectingAndThen(Collectors.toList(), list ->
                            new A(list.get(0).property1, list.get(0).property1)
                                    .avgProperty4(list).sumProperty3(list))
            )
    );
0 голосов
/ 27 августа 2018

Сбор до Map неизбежен, так как вы хотите group вещей. Грубый способ сделать это будет:

yourListOfA
      .stream()
      .collect(Collectors.groupingBy(
             x -> new Key(x.getProperty1(), x.getProperty2()),
             Collectors.collectingAndThen(Collectors.toList(),
                   list -> {
                        double first = list.stream().mapToDouble(A::getProperty3).sum();
                        // or any other default
                        double second = list.stream().mapToDouble(A::getProperty4).average().orElse(0D);
                        A a = list.get(0);
                        return new A(a.getProperty1(), a.getProperty2(), first, second);
            })))
     .values();

Это может быть немного улучшено, например, в Collectors.collectingAndThen для итерации List только один раз, для этого потребуется специальный сборщик. Не так сложно написать один ...

...