Java 流独立变量的最小值/最大值

标签 java java-8 java-stream max min

如何确定流中对象不同属性的minma​​x

我已经看到了有关如何获取相同变量的最小值和最大值的答案。我还看到了有关如何使用特定对象属性(例如 maxByAttribute() )获取最小值或最大值的答案。但是如何获得流中对象的所有“x”属性的最小值和所有“y”属性的最大值?

假设我有一个 Java Stream<Span>每个对象都有一个 Span.getStart()Span.getEnd()返回类型long 。 (单位无关;可能是时间或地板上的木板。)我想获得最小开始最大结束,例如表示覆盖所有跨度的最小跨度。当然,我可以创建一个循环并手动更新最小值和最大值,但是有没有一种使用 Java 流的简洁高效的函数方法?

请注意,我不想创建中间跨度!如果您想创建一些中间 Pair<Long>可以使用的实例,但出于我的目的,Span类型很特殊,我无法创建更多类型。我只想找到最小起点和最大终点。

还显示使用新的 Java 12 是否可以实现这一点 teeing() ,但就我的目的而言,该解决方案必须在 Java 8+ 中工作。

最佳答案

假设所有数据均有效 (end > start),您可以创建 LongSummaryStatistics通过使用 summaryStatistics() 作为终端操作,包含诸如最小/最大值、平均值等信息的对象。

List<Span> spans = // initiliazing the source
    
LongSummaryStatistics stat = spans.stream()
    .flatMapToLong(span -> LongStream.of(span.getStart(), span.getEnd()))
    .summaryStatistics();
        
long minStart = stat.getMin();
long maxEnd = stat.getMax();

注意,如果流源为空(您可以通过调用来检查它stat.getCount()将给出 LongSummaryStatistics 对象的消耗元素数量)、minmax 属性将有它们的默认值,分别是最大和最小长值。


这就是使用 collect() 并手动选择 maxmin 值来完成的方法:

long[] minMax = spans.stream()
    .collect(() -> new long[2],
        (long[] arr, Span span) -> { // consuming the next value
            arr[0] = Math.min(arr[0], span.getStart());
            arr[1] = Math.max(arr[1], span.getEnd());
        },
        (long[] left, long[] right) -> { // merging partial results produced in different threads
            left[0] = Math.min(left[0], right[0]);
            left[1] = Math.max(left[1], right[1]);
        });

为了使用Collectors.teeing(),您需要定义两个收集器和一个函数。流中的每个元素将同时被两个收集器使用,当它们完成时,merger 函数将获取它们的中间结果并产生最终结果。

在下面的示例中,结果是 map 条目的可选。如果流中没有元素,生成的可选对象也将为空。

List<Span> spans = List.of(new Span(1, 3), new Span(3, 6), new Span(7, 9));
        
Optional<Map.Entry<Long, Long>> minMaxSpan = spans.stream()
    .collect(Collectors.teeing(
        Collectors.minBy(Comparator.comparingLong(Span::getStart)),
        Collectors.maxBy(Comparator.comparingLong(Span::getStart)),
        (Optional<Span> min, Optional<Span> max) ->
            min.isPresent() ? Optional.of(Map.entry(min.get().getStart(), max.get().getEnd())) : Optional.empty()));
        
minMaxSpan.ifPresent(System.out::println);

输出

1=9

作为替代数据载体,您可以使用 Java 16 记录:

public record MinMax(long start, long end) {}

编译器将生成 start()end() 形式的 Getters。

关于Java 流独立变量的最小值/最大值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72144300/

相关文章:

java - 如何使用@WebServlet 接受参数(以 RESTFul 方式)?

java - 元素纹理为粉色/黑色

Rxjava2、Java 8 Streams、Plain Old Iteration 之间的性能比较

java - 使用 Java 8 流的两个 int 数组的笛卡尔积

java - 连接并行流

java - 将 PDF 文件更新为 mysql BLOB 您的 SQL 语法有误;

java - 从数组中删除项目并缩小数组

java - mvn 发布 :perform fails in java 8 - added javadoc plugin

java - 未经检查从 X 转换为扩展 X 的泛型类型

java - 增加 IntStream 外部的整数值