Java 8 сопоставить список с другим списком и подсчитать

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

Class Data {
  Date date;
  int int1;
  int int2;
}

class DataHistory {
  Date date;
   int sum_Int1_beforeOrEqualDate;
   int sum_Int2_beforeOrEqualDate;
   String someOtherValues;
}

Например, у меня есть несколько строк perDate со всеми значениями. Я бы хотел добиться:

Мой вклад:

date,    int1,  int2
01/01/18,  2,    3
01/01/18,  0,    1
02/01/18,  0,    1
02/01/18,  3,    0
03/01/18,  1,    3
...

Мой вывод:

date,    sum_Int1_beforeOrEqualDate,  sum_Int2_beforeOrEqualDate
01/01/18,  2,    4
02/01/18,  3,    1
03/01/18,  1,    3
...

Я пробовал несколько вещей, в основном с помощью Map, но никогда не мог сделать это с помощью List -> List.

Я пытался сделать следующее:

Обновлено: Моя последняя попытка, которая ясно показывает, что я не знаю, что делаю ..

List<OutputList> outputList =
inputlist
.stream()
.map( e -> new DataHistory())
.collect(Collectors.groupingBy(int1));

покажите то, что вы пытались лучше проиллюстрировать своим описанием.

Ousmane D. 21.04.2018 11:39

Как будут вычисляться два поля суммы?

akortex91 21.04.2018 11:40

Как бы вы вводили данные через консоль, вводя значения по одному или вводя данные через файл?

Tony Stark 21.04.2018 11:48

Мои входные значения поступают от объекта данных из базы данных. @Aris: Это просто сумма всех предыдущих значений до или равной даты

testeurFou 21.04.2018 12:01

Моим первым шагом было бы выбросить устаревший класс Date и вместо него ввести LocalDate из java.time. java.time - это современный Java API даты и времени, с которым гораздо приятнее работать. Date, несмотря на свое название, является моментом времени с точностью до миллисекунды, поэтому их много на одну дату, что может вызвать проблемы с фильтрацией.

Ole V.V. 21.04.2018 17:05

Вы хотите суммировать только за один и тот же день? Разве название sum_Int1_beforeOrEqualDate не вводит в заблуждение?

Ole V.V. 21.04.2018 17:07
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
1 073
3

Ответы 3

Я считаю, что вы пытаетесь просто суммировать значения, сгруппированные по дате. Итак, если вы проанализировали данные как список

List<Data> list = getDataAsList();
List<DataHistory> historyList = list.stream()
            .collect(Collectors.groupingBy(data -> data.date)).entrySet().stream()
            .map((entry) -> {
                DataHistory history = new DataHistory();
                history.date = entry.getKey();
                List<Data> dataList = entry.getValue();
                history.sum_Int1_beforeOrEqualDate = dataList.stream().mapToInt(data -> data.int1).sum();
                history.sum_Int2_beforeOrEqualDate = dataList.stream().mapToInt(data -> data.int2).sum();
                return history;
            })
            .collect(Collectors.toList());

Скажите, правильно ли я понял логику.

вместо того, чтобы дважды обходить dataList, чтобы получить суммы, вы можете сделать это за один раз, например, for (Data data : dataList){ history.sum_Int1_beforeOrEqualDate += data.int1; history.sum_Int2_beforeOrEqualDate += data.int2; }

Ousmane D. 21.04.2018 12:24

Решить поставленную задачу можно с помощью сборщика toMap:

Collection<DataHistory> resultSet = 
         myList.stream()
               .collect(Collectors.toMap(Data::getDate,
                        e -> new DataHistory(e.getDate(), e.getInt1(), e.getInt2(), null),
                        DataHistory::merge)).values();

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

public DataHistory(Date date, int sum_Int1_beforeOrEqualDate, 
          int sum_Int2_beforeOrEqualDate, String someOtherValues) {
        this.date = date;
        this.sum_Int1_beforeOrEqualDate = sum_Int1_beforeOrEqualDate;
        this.sum_Int2_beforeOrEqualDate = sum_Int2_beforeOrEqualDate;
        this.someOtherValues = someOtherValues;
}

и функция merge, определенная как таковая:

public DataHistory merge(DataHistory other){
        this.sum_Int1_beforeOrEqualDate += other.getSum_Int1_beforeOrEqualDate();
        this.sum_Int2_beforeOrEqualDate += other.getSum_Int2_beforeOrEqualDate();
        return this;
}

в классе DataHistory.


Кроме того, если вам явно требуется List<DataHistory>, а не Collection<DataHistory>, вы можете:

 List<DataHistory> historyList = new ArrayList<>(resultSet); 

Обратите внимание, что я передаю null конструктору DataHistory для четвертого параметра просто потому, что не знаю, какие данные передать, поэтому я оставлю это на ваше усмотрение.

Что вы могли бы сделать, так это использовать Collections.reducing, который работает довольно хорошо.

List<DataHistory> dataHistories = 
                   list.stream()
                       .collect(Collectors.groupingBy(Data::getDate, 
                                Collectors.reducing(DataHistory::new,
                                                    DataHistoryHelper::merge)))
                       .values();

Это решение предполагает, что у вас есть конструктор в DataHistory, принимающий Data в качестве параметра.

public DataHistory(Data o) {
    this.date = o.getDate();
    // and so on
}

И что у вас есть метод (где угодно), который заботится о слиянии двух объектов DataHistory.

public DataHistory merge(DataHistory o1, DataHistory o2) {
    DataHistory merged = new DataHistory();
    merged.setSum_Int1_beforeOrEqualDate(o1.getSum_Int1_beforeOrEqualDate + o2.getSum_Int1_beforeOrEqualDate);
    // and so on
    return merged;
}

Другие вопросы по теме