получить общее количество ArrayList, сгруппированных по дате с использованием лямбда-функций в Java 8 - PullRequest
0 голосов
/ 28 августа 2018

У меня есть класс модели для Счета-фактуры, в котором указана дата совершения покупки и цена.

Class Invoice{
    Date purchaseDate;
    BigDecimal price;
    //getters and setters
}

Я получаю список счетов, который содержит все счета за продукт, проданный за один месяц:

List<Invoice> invoiceListForMonth;

Я хочу получить общий объем продаж за каждый день месяца.

List<BigDecimal> dayWiseSales;

Как я могу получить данные в списке, используя лямбда-функции с Java 8?

Ответы [ 4 ]

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

С фактической структурой, используемой в вашем вопросе, вы можете собрать значения BigDecimal, сгруппированные по дням месяца в Map<Integer, List<BigDecimal>>.
Затем сложите их для каждой записи и соберите в Map<Integer, BigDecimal>.

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toList;

// ...

List<Invoice> invoiceListForMonth = ... ;

Map<Integer, BigDecimal> sumByDayOfMonth = 
invoiceListForMonth.stream()
                  .collect(groupingBy(i -> i.getPurchaseDate()
                                            .getDate(),
                                      mapping(Invoice::getPrice, toList())))
                  // Map<Integer, List<BigDecimal>> is produced above
                  .entrySet()
                  .stream()
                  .collect(toMap(Entry::getKey, entry -> entry.getValue()
                                                              .stream()
                                                              .reduce(BigDecimal.ZERO, BigDecimal::add)));
0 голосов
/ 28 августа 2018

Я думаю, вам нужно что-то вроде этого:

List<Invoice> invoiceListForMonth = new ArrayList<>();
//add some data
Map<LocalDate, BigDecimal> result =
        invoiceListForMonth.stream()
                .collect(Collectors.groupingBy(
                        Invoice::getPurchaseDate
                )).entrySet().stream()//This will return a map of Map<LocalDateTime, List<Invoice>>
                .collect(Collectors.toMap(Map.Entry::getKey, // to collect with the date
                        e -> e.getValue().stream().map(Invoice::getPrice) //and the sum of
                                .reduce(BigDecimal.ZERO, BigDecimal::add)) // prices
                );

Чтобы лучше это понять Вы можете разделить свою работу в два этапа:

Map<LocalDateTime, List<Invoice>> grouping =
        invoiceListForMonth.stream()
                .collect(Collectors.groupingBy(Invoice::getPurchaseDate));

Map<LocalDate, BigDecimal> result = grouping.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                e -> e.getValue().stream().map(Invoice::getPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add))
        );

Демонстрация конкретного примера


Заметьте, я использовал LocalDate из java.time API, потому что Date устарел, и я больше не предлагаю его использовать.


Редактировать

на самом деле класс Invoice используется во многих других местах, поэтому я не может изменить его на LocalDate. Я пытался реализовать это с помощью даты, но моя коллекция сгруппирована по дате и времени. Я хочу сгруппировать используя только дата Можете ли вы что-то предложить?

На основе вашего комментария вы можете создать свой собственный метод, который удалит часть времени из даты, чтобы вы могли сравнивать только часть даты следующим образом:

public static Date getDateWithoutTime(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}

Затем вы можете вызвать метод в groupingBy следующим образом:

Map<Date, List<Invoice>> grouping =
        invoiceListForMonth.stream()
                .collect(Collectors.groupingBy(
                        p -> getDateWithoutTime(p.getPurchaseDate())
                ));
Map<Date, BigDecimal> result = grouping.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                e -> e.getValue().stream().map(Invoice::getPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add))
        );

Примечание: я настоятельно не рекомендую использовать этот старый API, вместо этого вы можете перейти на java.time, это вам очень поможет.

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

Прежде всего, вы должны использовать LocalDate вместо Date.

Чтобы получить обзор по каждому продукту, вы можете легко преобразовать свой List<Invoice> invoiceListForMonth в соответствующую карту следующим образом:

final Map<LocalDate, BigDecimal> dateBigDecimalMap = listinvoiceListForMonth
               .stream()
               .sorted(Comparator.comparing(Invoice::getPurchaseDate))
               .collect(Collectors.toMap(
                        Invoice::getPurchaseDate,
                        Invoice::getPrice,
                        BigDecimal::add));

После этого вы можете создать List<BigDecimal> dayWiseSales в одной записи:

final List<BigDecimal> dayWiseSales = dateBigDecimalMap.values();
0 голосов
/ 28 августа 2018

Прежде всего, используйте LocalDate вместо Date. Тогда должно быть что-то вроде этого:

class Scratch {
    public static void main(String[] args) {
        List<Invoice> invoices = Arrays.asList(
                new Invoice(LocalDate.now(), BigDecimal.ONE),
                new Invoice(LocalDate.now().minusDays(1), BigDecimal.TEN),
                new Invoice(LocalDate.now(), BigDecimal.TEN)
        );

        Month requiredMonth = LocalDate.now().getMonth();

        Map<LocalDate, BigDecimal> invoicesByDate = invoices.stream()
                .collect(Collectors.groupingBy(Invoice::getPurchaseDate, // group invoices by Purchase Date
                        Collectors.mapping(Invoice::getPrice,
                        Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));

        System.out.println(invoicesByDate); // {2018-08-28=11, 2018-08-27=10}
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...