Я хочу создать список значений истории для существующего списка, чтобы я мог сохранить его в БД для отображения позже в таблице
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));
Как будут вычисляться два поля суммы?
Как бы вы вводили данные через консоль, вводя значения по одному или вводя данные через файл?
Мои входные значения поступают от объекта данных из базы данных. @Aris: Это просто сумма всех предыдущих значений до или равной даты
Моим первым шагом было бы выбросить устаревший класс Date и вместо него ввести LocalDate из java.time. java.time - это современный Java API даты и времени, с которым гораздо приятнее работать. Date, несмотря на свое название, является моментом времени с точностью до миллисекунды, поэтому их много на одну дату, что может вызвать проблемы с фильтрацией.
Вы хотите суммировать только за один и тот же день? Разве название sum_Int1_beforeOrEqualDate не вводит в заблуждение?




Я считаю, что вы пытаетесь просто суммировать значения, сгруппированные по дате. Итак, если вы проанализировали данные как список
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; }
Решить поставленную задачу можно с помощью сборщика 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;
}
покажите то, что вы пытались лучше проиллюстрировать своим описанием.