代码之家  ›  专栏  ›  技术社区  ›  Zed

从列表中检索多个最小事件

  •  3
  • Zed  · 技术社区  · 6 年前

    我有一个自定义对象列表:

    List<CustomObject> customObjects;
    

    我希望从中提取设置了最早日期时间值的所有对象。

    所以这个类看起来是这样的:

    class CustomObject {
       LocalDateTime date;
    
       public LocalDateTime getDateTime() {
           return date;
       }
    }
    

    我可以通过这样一个定制的比较器函数成功地在列表中找到最早日期的对象:

    private static LocalDateTime getDate(CustomObject customObject) {
            return customObject.getDateTime();
    }
    
    CustomObject customObjectMin = customObjects.stream().
               min(Comparator.comparing(MyUtilClass::getDate));
    

    但是,有可能有多个具有相同日期的自定义对象,但在该场景中,似乎没有办法使用 min . 是否有一个简单的解决方案来查找列表中具有最早日期集的所有对象?像这样:

    List<CustomObject> customObjectsMin = customObjects.stream().
               minWithAllOccurences(Comparator.comparing(MyUtilClass::getDate));
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   Peter Lawrey    6 年前

    你可以做两个选择。

    • 一个用来查找最小日期的
    • 一个找到那个日期的人

    例如

    LocalDate min = customObjects.stream()
                                 .map(CustomObject::getDateTime)
                                 .min(Comparator.naturalOrder());
    List<CustomObject> objs = customObjects.stream()
                                 .filter(c -> min.equals(c.getDateTime()))
                                 .collect(Collectors.toList());
    

    或者,您可以使用Collectors.GroupingBy进入树映射并获取第一个条目。

        2
  •  0
  •   Patrick Parker    6 年前

    除了Peter Lawrey的优秀答案,我想指出的是,在避免将每个元素收集到treemap中的内存开销的同时,可以使用单个流来完成这项工作。怎样?一种方法是 reduce() ,如下:

    List<SampleJava> customObjectsMin = customObjects.stream()
            .reduce(new ArrayList<>(), // identity
            (List<SampleJava> list, SampleJava item) -> { // accumulate
                if(list.isEmpty() ||  getDate(item).compareTo(getDate(list.get(0))) < 0) {
                    return new ArrayList<>(Arrays.asList(item));
                } else if(getDate(item).equals(getDate(list.get(0)))) {
                    list.add(item);
                }
                return list;
            },
            (list1, list2) -> { // combine
                if(list1.isEmpty()) return list2; 
                if(list2.isEmpty()) return list1; 
                int cmp = getDate(list1.get(0)).compareTo(getDate(list2.get(0)));
                if(cmp < 0) return list1;
                if(cmp > 0) return list2;
                list1.addAll(list2);
                return list1;
            });