Java 8 条流减少删除重复项,保留最新条目
Java 8 Streams reduce remove duplicates keeping the most recent entry
我有一个 Java bean,比如
class EmployeeContract {
Long id;
Date date;
getter/setter
}
如果有一长串这些,其中我们有重复的 ID 但日期不同,例如:
1, 2015/07/07
1, 2018/07/08
2, 2015/07/08
2, 2018/07/09
如何减少这样的列表,只保留最近日期的条目,例如:
1, 2018/07/08
2, 2018/07/09
?
最好使用 Java 8...
我从类似的东西开始:
contract.stream()
.collect(Collectors.groupingBy(EmployeeContract::getId, Collectors.mapping(EmployeeContract::getId, Collectors.toList())))
.entrySet().stream().findFirst();
这为我提供了各个组内的映射,但我不知道如何将其收集到结果列表中 - 恐怕我的流不是太强...
您可以分两步完成:
List<EmployeeContract> finalContract = contract.stream() // Stream<EmployeeContract>
.collect(Collectors.toMap(EmployeeContract::getId,
EmployeeContract::getDate, (a, b) -> a.after(b) ? a : b)) // Map<Long, Date> (Step 1)
.entrySet().stream() // Stream<Entry<Long, Date>>
.map(a -> new EmployeeContract(a.getKey(), a.getValue())) // Stream<EmployeeContract>
.collect(Collectors.toList()); // Step 2
第一步:确保将 date
与最近映射到 id
的比较。
第二步:将这些键、值对映射到最终的List<EmployeeContract>
结果。
好吧,我只是将我的评论以答案的形式放在这里:
yourList.stream()
.collect(Collectors.toMap(
EmployeeContract::getId,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(EmployeeContract::getDate)))
)
.values();
这会给你 Collection
而不是 List
,如果你真的关心这个的话。
使用 vavr.io 你可以这样做:
var finalContract = Stream.ofAll(contract) //create io.vavr.collection.Stream
.groupBy(EmployeeContract::getId)
.map(tuple -> tuple._2.maxBy(EmployeeContract::getDate))
.collect(Collectors.toList()); //result is list from java.util package
只是为了补充现有答案,如您所问:
how to collect that into a result list
这里有一些选项:
将 values()
换成 ArrayList
:
List<EmployeeContract> list1 =
new ArrayList<>(list.stream()
.collect(toMap(EmployeeContract::getId,
identity(),
maxBy(comparing(EmployeeContract::getDate))))
.values());
将 toMap
收集器包装成 collectingAndThen
:
List<EmployeeContract> list2 =
list.stream()
.collect(collectingAndThen(toMap(EmployeeContract::getId,
identity(),
maxBy(comparing(EmployeeContract::getDate))),
c -> new ArrayList<>(c.values())));
使用另一个流将 values
收集到新的 List
:
List<EmployeeContract> list3 =
list.stream()
.collect(toMap(EmployeeContract::getId,
identity(),
maxBy(comparing(EmployeeContract::getDate))))
.values()
.stream()
.collect(toList());
我有一个 Java bean,比如
class EmployeeContract {
Long id;
Date date;
getter/setter
}
如果有一长串这些,其中我们有重复的 ID 但日期不同,例如:
1, 2015/07/07
1, 2018/07/08
2, 2015/07/08
2, 2018/07/09
如何减少这样的列表,只保留最近日期的条目,例如:
1, 2018/07/08
2, 2018/07/09
? 最好使用 Java 8...
我从类似的东西开始:
contract.stream()
.collect(Collectors.groupingBy(EmployeeContract::getId, Collectors.mapping(EmployeeContract::getId, Collectors.toList())))
.entrySet().stream().findFirst();
这为我提供了各个组内的映射,但我不知道如何将其收集到结果列表中 - 恐怕我的流不是太强...
您可以分两步完成:
List<EmployeeContract> finalContract = contract.stream() // Stream<EmployeeContract>
.collect(Collectors.toMap(EmployeeContract::getId,
EmployeeContract::getDate, (a, b) -> a.after(b) ? a : b)) // Map<Long, Date> (Step 1)
.entrySet().stream() // Stream<Entry<Long, Date>>
.map(a -> new EmployeeContract(a.getKey(), a.getValue())) // Stream<EmployeeContract>
.collect(Collectors.toList()); // Step 2
第一步:确保将 date
与最近映射到 id
的比较。
第二步:将这些键、值对映射到最终的List<EmployeeContract>
结果。
好吧,我只是将我的评论以答案的形式放在这里:
yourList.stream()
.collect(Collectors.toMap(
EmployeeContract::getId,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(EmployeeContract::getDate)))
)
.values();
这会给你 Collection
而不是 List
,如果你真的关心这个的话。
使用 vavr.io 你可以这样做:
var finalContract = Stream.ofAll(contract) //create io.vavr.collection.Stream
.groupBy(EmployeeContract::getId)
.map(tuple -> tuple._2.maxBy(EmployeeContract::getDate))
.collect(Collectors.toList()); //result is list from java.util package
只是为了补充现有答案,如您所问:
how to collect that into a result list
这里有一些选项:
将
values()
换成ArrayList
:List<EmployeeContract> list1 = new ArrayList<>(list.stream() .collect(toMap(EmployeeContract::getId, identity(), maxBy(comparing(EmployeeContract::getDate)))) .values());
将
toMap
收集器包装成collectingAndThen
:List<EmployeeContract> list2 = list.stream() .collect(collectingAndThen(toMap(EmployeeContract::getId, identity(), maxBy(comparing(EmployeeContract::getDate))), c -> new ArrayList<>(c.values())));
使用另一个流将
values
收集到新的List
:List<EmployeeContract> list3 = list.stream() .collect(toMap(EmployeeContract::getId, identity(), maxBy(comparing(EmployeeContract::getDate)))) .values() .stream() .collect(toList());