Java 8流减少了保留最新条目的删除重复项

时间:2018-11-27 17:12:41

标签: java java-8 java-stream reduction

我有一个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();

这使我可以在各个组中进行映射,但是我对如何将其收集到结果列表中感到困惑-恐怕我的流不太强...

4 个答案:

答案 0 :(得分:6)

好吧,我将在这里以回答的形式发表我的评论:

 yourList.stream()
         .collect(Collectors.toMap(
                  EmployeeContract::getId,
                  Function.identity(),
                  BinaryOperator.maxBy(Comparator.comparing(EmployeeContract::getDate)))
            )
         .values();

如果您真的很在意,这将为您提供Collection而不是List

答案 1 :(得分:1)

您可以按照以下两个步骤进行操作:

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>

答案 2 :(得分:1)

仅是对现有答案的补充,如您所愿:

  

如何将其收集到结果列表中

以下是一些选择:

  • 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());
    

答案 3 :(得分:0)

使用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