I have a list of objects like this:
MyObject {
Date date;
int value;
}
I want to iterate the list and only keeps the objects where the dates differ. If there are two objects with the same date then I want to keep the object with the bigger value. Can this be achieved by using streams and predicates somehow?
CodePudding user response:
Yes, you can use stream
to filter distinct elements:
public class MyObject {
private final LocalDate date;
private final int value;
public MyObject(LocalDate date, int value) {
this.date = date;
this.value = value;
}
public final LocalDate getDate() {
return date;
}
public final int getValue() {
return value;
}
@Override
public String toString() {
return "[date=" date ", value=" value "]";
}
}
To get distinct elements you can do:
public static Collection<MyObject> getDistinct(List<MyObject> list) {
return list.stream().collect(
Collectors.groupingBy(MyObject::getDate,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(MyObject::getValue)),
Optional::get)))
.values();
}
Then:
List<MyObject> list = List.of(new MyObject(LocalDate.of(2021, 1, 1), 1),
new MyObject(LocalDate.of(2021, 1, 1), 2),
new MyObject(LocalDate.of(2022, 2, 2), 2));
Collection<MyObject> distinct = getDistinct(list);
distinct.forEach(System.out::println);
Output:
[date=2022-02-02, value=2]
[date=2021-01-01, value=2]
Note: I would use LocalDate
instead of Date
CodePudding user response:
You should use Map
and Map.merge()
instread of Stream
.
record MyObject(Date date, int value) {}
public static void main(String[] args) {
List<MyObject> list = List.of(
new MyObject(new Date(0), 0),
new MyObject(new Date(0), 1),
new MyObject(new Date(1000), 2));
Map<Date, MyObject> map = new LinkedashMap<>();
for (MyObject e : list)
map.merge(e.date(), e, (a, b) -> a.value() > b.value() ? a : b);
list = new ArrayList<>(map.values());
for (MyObject e : list)
System.out.println(e);
}
output:
MyObject[date=Thu Jan 01 09:00:00 JST 1970, value=1]
MyObject[date=Thu Jan 01 09:00:01 JST 1970, value=2]