Java лямбда - Попытка суммировать по 2 группам - PullRequest
0 голосов
/ 01 марта 2019

У меня есть список объектов, который мне нужно сгруппировать по 2 различным атрибутам, а затем суммировать значения атрибута, структура моего объекта выглядит примерно так:

private Long id1;
private Long id2;
private Double amountReserved;
private Double amountRequired;
//... more atributes and getters and setters

Итак, я тогдау меня есть список, например:

List<MyList> list = Arrays.asList(
list(1, A, 50, 200)
list(1, A, 50, 200)
list(1, B, 0, 100)
list(2, A, 10, 15)
list(2, A, 5, 15)
list(3, A, 0, 25));

То, что я пытаюсь достичь, - это новый список со следующей структурой:

list(1, A, 100, 100) 
list(1, B,   0, 100)
list(2, A,  15,   0)
list(3, A,   0,  25)

Выяснение того, что я пытаюсь достичь:

  1. Группировка объектов по id1 и id2
  2. сумма amountReserved сгруппированного объекта
  3. вычитание amountRequired из суммированных amountReserved

Что у меня есть на данный момент:

Это дает мне группировки, как я хотел

Map<Long, Map<String, List<MyList>>> map = null;
map = lista.stream().collect(Collectors.groupingBy(PreSeparacaoDto::getCodigoPedido,
                    Collectors.groupingBy(PreSeparacaoDto::getCodigoProduto)));

Это сумма по группам id1, ноЯ изо всех сил пытаюсь добавить в него вторую группировку, так как получаю синтаксические ошибки:

lista.stream()
        .collect(Collectors.groupingBy(PreSeparacaoDto::getCodigoPedido,
                Collectors.summingDouble(PreSeparacaoDto::getProdutoQuantidadeSeparada)))
        .forEach((codigoPedido, ProdutoQuantidadeSeparada) -> System.out.println( codigoPedido + ": " + ProdutoQuantidadeSeparada  ));

Моя проблема в том, что мне не удалось собрать их вместе (в соответствии с реквизитом 2), и я даже не был близок к достижению моегореквизит 3.

Я пытался использовать сокращение, как объяснено здесь , но, честно говоря, я был нне в состоянии повторить это с одной группировкой, сокращение возвращает ошибку, сообщающую, что мои параметры не соответствуют параметрам reducing.Я искал другие варианты здесь на stackoverflow и других веб-сайтах, но безуспешно.

Может ли кто-нибудь мне помочь и подсказать, где мне не удается объединить сокращение с моей группой, или если это правильный путь, который ядолжно быть следующее.

Ответы [ 4 ]

0 голосов
/ 01 марта 2019

вы можете выполнить упорядочение по id1, а затем упорядочить id2 (чтобы убедиться, что элементы одного и того же списка и подсписка следуют друг за другом), а затем выполнить вложенный foreach (перед тем, как выполнить итерацию подсписка, вы инициируете result_reserved_amount равным 0 и result_required_amount дляначальное значение), тогда вы делаете, если идентичные идентификаторы (если id1 = previous_id1 и id2 = previous_id2) делают result_reserved_amount + = current_reserved_amount и result_required_amount - = current_reserved_amount, в противном случае обновите previous_id1, previous_id2, result_reserved_amount, result_required_amount * 1001

0 голосов
/ 01 марта 2019

Я думаю, что проще всего использовать Collectors.grouping: вы говорите, как группировать и что собирать.

Вот пример, вычисляющий только сумму AmountReserved:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class GroupedSums {

    static class MyList {
        Long id1;
        char id2;
        Double amountReserved;
        Double amountRequired;
        public Long getId1() {
            return id1;
        }
        public char getId2() {
            return id2;
        }
        public Double getAmountReserved() {
            return amountReserved;
        }
        public Double getAmountRequired() {
            return amountRequired;
        }
        public MyList(Long id1, char id2, Double amountReserved, Double amountRequired) {
            super();
            this.id1 = id1;
            this.id2 = id2;
            this.amountReserved = amountReserved;
            this.amountRequired = amountRequired;
        }

        Key key() {
            return new Key(id1, id2);
        }

    }

    private static MyList list(Long id1, char id2, Double amountReserved, Double amountRequired) {
        return new MyList(id1, id2, amountReserved, amountRequired);
    }

    public GroupedSums() {      
    }

    private static class Key {

        Long id1;
        char id2;
        public Long getId1() {
            return id1;
        }
        public char getId2() {
            return id2;
        }
        public Key(Long id1, char id2) {
            super();
            this.id1 = id1;
            this.id2 = id2;
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((id1 == null) ? 0 : id1.hashCode());
            result = prime * result + id2;
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Key other = (Key) obj;
            if (id1 == null) {
                if (other.id1 != null)
                    return false;
            } else if (!id1.equals(other.id1))
                return false;
            if (id2 != other.id2)
                return false;
            return true;
        }
        @Override
        public String toString() {
            return "[id1=" + id1 + ", id2=" + id2 + "]";
        }   

    }

    public static void main(String[] args) {
        List<MyList> list = Arrays.asList(
                list(1L, 'A', 50d, 200d),
                list(1L, 'A', 50d, 200d),
                list(1L, 'B', 0d, 100d),
                list(2L, 'A', 10d, 15d),
                list(2L, 'A', 5d, 15d),
                list(3L, 'A', 0d, 25d));

        list.stream().collect(Collectors.groupingBy(MyList::key, Collectors.summingDouble(MyList::getAmountReserved)))
        .forEach((k,v)->System.out.println("" + k + " :" + v));
    }

}

HTH!

0 голосов
/ 01 марта 2019

Возможно, вы просто ищете Collectors.toMap как:

List<MyList> output = new ArrayList<>(lista.stream()
        .collect(Collectors.toMap(a -> a.getId1() + "-" + a.getId2(), a -> a, (myList1, myList2) -> {
            myList1.amountReserved = myList1.amountReserved + myList2.amountReserved;
            myList1.amountRequired = myList1.amountRequired - myList1.amountReserved;
            return myList1;
        })).values());
0 голосов
/ 01 марта 2019

Вы можете дважды просмотреть список ввода.

В первый раз вы группируете по id1, id2 и вычисляете сумму зарезервированной суммы.Во второй раз вы можете снова воспроизвести список, сгруппировать его (по id1 и id2), используя приведенный выше результат, чтобы найти разницу.

Map<Long, Map<Long, Double>> amountReservedGroup = list.stream()
        .collect(Collectors.groupingBy(MyList::getId1, Collectors.groupingBy(MyList::getId2,
                Collectors.summingDouble(MyList::getAmountReserved))));


Map<Long, Map<Long, List<MyList>>> finalResult = list.stream()
        .collect(Collectors.groupingBy(MyList::getId1, Collectors.groupingBy(MyList::getId2,
                Collectors.mapping(o -> new MyList(o.getId1(), o.getId2(),
                                amountReservedGroup.get(o.getId1()).get(o.getId2()),
                                o.getAmountRequired() - amountReservedGroup.get(o.getId1()).get(o.getId2())),
                        Collectors.toList()))));

Примечание: Это необработать случай, когда результат вычитания будет отрицательным !!

Как указано в комментариях nullpointer @, будет ли значение amountRequired одинаковым для заданных id1 и id2?

...