Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
获取Java8流的最小值和最大值的简明方法_Java_Java Stream - Fatal编程技术网

获取Java8流的最小值和最大值的简明方法

获取Java8流的最小值和最大值的简明方法,java,java-stream,Java,Java Stream,是否有一种简洁的方法(基于某些比较器)一次性提取流的最小值和最大值 似乎有很多方法可以分别获取最小值和最大值,或者我可以将流排序为临时对象,例如: List<T> sorted = Stream.of(...).sorted().collect(Collectors.toList()); T min = sorted.get(0); T max = sorted.get(sorted.size() - 1); List sorted=Stream.of(…).sorted().co

是否有一种简洁的方法(基于某些比较器)一次性提取流的最小值和最大值

似乎有很多方法可以分别获取最小值和最大值,或者我可以将流排序为临时对象,例如:

List<T> sorted = Stream.of(...).sorted().collect(Collectors.toList());
T min = sorted.get(0);
T max = sorted.get(sorted.size() - 1);
List sorted=Stream.of(…).sorted().collect(Collectors.toList());
T min=sorted.get(0);
T max=sorted.get(sorted.size()-1);
但这并不简洁,需要分配一个临时对象。我不希望分配一个临时对象或在流中进行两次传递。还有别的选择吗

Pair<T> extent = Stream.of(...).???
Pair extent=Stream.of(…)。???

将流的每个元素映射到一对,其中两个元素表示最小值和最大值;然后通过取最小值和最大值来减少对

例如,使用一些
类和一些
比较器

比较器比较器=。。。; 可选的minMax=list.stream() .map(i->Pair.of(i/*“min”*/,i/*“max”*/) .减少((a,b)->一对( //最小元素的最小值。 比较器。比较(a.first,b.first)<0?a.first:b.first, //最大元素的最大值。 比较器。比较(a.秒,b.秒)>0?a.秒:b.秒);
使用任何可变
对的简单方法
类:

final Pair<T, T> pair = new Pair<>();
final Comparator<T> comparator = ...;
Stream.of(...).forEachOrdered(e -> {
    if(pair.first == null || comparator.compare(e, pair.first) < 0){
        pair.first = e;
    }
    if(pair.second == null || comparator.compare(e, pair.second) > 0){
        pair.second = e;
    }
});
final Pair=新Pair();
最终比较器比较器=。。。;
(…).forEachOrdered的流(e->{
if(pair.first==null | | comparator.compare(e,pair.first)<0){
pair.first=e;
}
if(pair.second==null | | comparator.compare(e,pair.second)>0){
第二对=e;
}
});

对于相当简洁的纯Java解决方案,您可以使用.peek()。这不是真正的功能,因为.peek()所做的任何事情都是一种副作用。但这一过程可以一次性完成,不需要排序,也不太冗长。有一个“temp”对象,即AtomicRef,但是您可能会分配一个本地var/ref来保存最小值和最大值

Comparator<T> cmp = ...
Stream<T> source = ...
final AtomicReference<T> min = new AtomicReference<T>();
Optional<T> max = source.peek(t -> {if (cmp.compare(t,min.get()) < 0) min.set(t);})
    .max(cmp);
//Do whatever with min.get() and max.get()
比较器cmp=。。。 流源=。。。 最终原子引用最小值=新原子引用(); 可选max=source.peek(t->{if(cmp.compare(t,min.get())<0)min.set(t);}) .max(cmp); //使用min.get()和max.get()执行任何操作
如果这是一项经常需要的功能,我们最好制作一个
收集器来完成这项工作。我们需要一个
Stats
类来保存
count、min、max
和工厂方法来创建Stats收集器

Stats<String> stats = stringStream.collect(Stats.collector())

fooStream.collect(Stats.collector(fooComparator))
DoubleSummaryStatistics stats2 = Stream.of(2.4, 4.3, 3.3, 2.5)
  .collect(Collectors.summarizingDouble((Double::doubleValue)));

如果您有一个整数流,
summaringit
收集器工作良好

IntSummaryStatistics stats = Stream.of(2,4,3,2)
      .collect(Collectors.summarizingInt(Integer::intValue));

int min = stats.getMin();
int max = stats.getMax();
如果您有Double,您可以使用
SummaringDouble
收集器

Stats<String> stats = stringStream.collect(Stats.collector())

fooStream.collect(Stats.collector(fooComparator))
DoubleSummaryStatistics stats2 = Stream.of(2.4, 4.3, 3.3, 2.5)
  .collect(Collectors.summarizingDouble((Double::doubleValue)));
我想你需要这个

IntStream myIntStream = IntStream.rangeClosed(1, 100);
IntSummaryStatistics intStatistic = myIntStream.summaryStatistics();

System.out.println("Max: " + intStatistic.getMax() + " Min: " + intStatistic.getMin());

从Java 12开始,通过使用
Collectors::teeing
,您可以在一次传递中获得两个或更多结果:

class Movie {
    String title;
    double rating;
    //...
}

class Pair<T1, T2> {
    T1 left;
    T2 right;
    //...
}

@Test
void shouldFindWorstAndBestMovie() {
    var m1 = new Movie("Groundhog Day", 8);
    var m2 = new Movie("Stop! Or My Mom Will Shoot", 4.4);
    var m3 = new Movie("Forrest Gump", 8.8);

    var ratingComparator = Comparator.comparing(Movie::getRating);

    Pair<Movie, Movie> result = Stream.of(m1, m2, m3)
            .collect(Collectors.teeing(
                    Collectors.minBy(ratingComparator),
                    Collectors.maxBy(ratingComparator),
                    (min, max) -> new Pair<>(min.orElse(null), max.orElse(null))
            ));

    assertEquals(m2, result.getLeft(), "min does not match");
    assertEquals(m3, result.getRight(), "max does not match");
}
类电影{
字符串标题;
双重评级;
//...
}
类对{
T1左;
T2右;
//...
}
@试验
void shouldFindWorstBestMovie()应为空{
var m1=新电影(“土拨鼠日”,8);
var m2=新电影(“停止!否则我妈妈会拍”,4.4);
var m3=新电影(《阿甘正传》,第8.8节);
var ratingComparator=比较器。比较(Movie::getRating);
配对结果=流量(m1、m2、m3)
收集(
收集器。minBy(额定比较器),
收集器。maxBy(额定比较器),
(最小值,最大值)->新对(最小值或最小值(null),最大值或最小值(null))
));
assertEquals(m2,result.getLeft(),“min不匹配”);
assertEquals(m3,result.getRight(),“最大值不匹配”);
}

您可以在中找到更多详细信息和示例。

您是否考虑过像这样的收藏家?假设这不是关于数字,你可以遵循这个模式。不像我希望的那样简洁,但这看起来不错。如果有一个Comparator.min()和Comparator.max()来简化最后两行就好了。番石榴中有一对吗?番石榴没有一对。你是说Apache Commons吗?哎呀。嗯,实施并不是特别相关。我将其保留在“some
Pair
”。我不会指定
无序的
,因为此收集器能够尊重遭遇顺序,即,如果有平局,则提供第一个最大/最小元素,就像
max(…)
min(…)
一样。
IntSummaryStatistics
更好。。。这取决于
max
必须消耗整个
源流
-流-我不确定这是否有任何保证(认为已排序的源,短路可能是可能的?)。OP在原始问题中排序,希望避免它。是什么让你相信不能保证使用流。max(cmp)和.peek()都是在java.util.stream.stream接口上定义的,除了在管道处理过程中引发的异常之外,没有什么可以阻止这一点……我同意这种方法适用于当前版本——我只是想知道它是否保证在将来的版本中继续工作(例如,请参阅,如果java 9能够以更有效的方式确定大小,它将不再访问所有元素)。但是,使用自定义的
比较器
,这种优化在这里可能是不可能的。根据J9 API,
max()
是终端,但不是短路。我无法想象一个实现会在接受排序流的
max()
之外短路(OP想要避免)。我喜欢这个!