Java 在流中查找对应于后映射最小值的前映射元素

Java 在流中查找对应于后映射最小值的前映射元素,java,reduce,Java,Reduce,我经常发现自己在做这样的事情: list.stream().min(new Comparator<>() { @Override public int compare(E a, E b) { return Double.compare(f(a),f(b)); } }) 但是我不知道如何得到这个最小值对应的原始元素 一个丑陋的方法是 class WithF<E>{ private final E e; privat

我经常发现自己在做这样的事情:

list.stream().min(new Comparator<>() {

    @Override
    public int compare(E a, E b) {
        return Double.compare(f(a),f(b));
    }
})
但是我不知道如何得到这个最小值对应的原始元素

一个丑陋的方法是

class WithF<E>{
    private final E e;
    private final double fe;
    WithF(E e, double fe){
        this.e = e;
        this.fe = fe;
    }
    public E getE(){
        return e;
    }
    public double getFE(){
        return fe;
    }
}
使用f类{
私人期末考试;
私人最终双fe;
带F(E,双fe){
这个。e=e;
这个.fe=fe;
}
公共E getE(){
返回e;
}
公共双getFE(){
返回fe;
}
}
然后

list.stream().map(e -> new WithF<>(e,f(e))).min(Comparator.comparingDouble(WithF::getFE))
list.stream().map(e->newwithf(e,f(e))).min(Comparator.comparingDouble(WithF::getFE))
有没有更好的、惯用的方法来使用流API实现这一点?

如何:

Optional<E> minE = list.stream()
    .map(e -> new AbstractMap.SimpleEntry(e, f(e))
    .min(Map.Entry.comparingByValue())
    .map(Map.Entry::getKey);
Optional minE=list.stream()
.map(e->new AbstractMap.SimpleEntry(e,f(e))
.min(Map.Entry.comparingByValue())
.map(map.Entry::getKey);
这实际上是为每个列表项创建一个映射条目,然后使用这些值查找
min
条目,最后获得匹配的键

请注意,它返回一个
可选
,以允许列表中没有项目的情况,在这种情况下,您将得到一个
。或者,如果列表为空,您可以在末尾添加一个
或lse
调用以返回另一个
E


Map.Entry的使用有点不寻常(即不将其放入地图中)。有些库具有
类,可以完成相同的工作,也可以创建自己的类。

等待时,我将发布我当前考虑的内容:

List<Double> fs = list.stream()
    .map(e -> f(e))
    .collect(Collectors.toList())
int i = IntStream.range(0,fs.size()).boxed()
    .min(java.util.Comparator.comparingDouble(fs::get))
    .get();
list.get(i)
List fs=List.stream()
.地图(东->东)
.collect(收集器.toList())
inti=IntStream.range(0,fs.size()).boxed()
.min(java.util.Comparator.comparingDouble(fs::get))
.get();
列表。获取(i)

此转换通常称为

实际上,我会用f来概括
,并加上一些额外的位,然后将其重命名以使管道更整洁

class SchwartzianKV<E, SORTKEY implements Comparable<SORTKEY> > 
      implements Comparable<SchwartzianKV<E, SORTKEY>> {

    public final E e;
    public final SORTKEY sortkey;

    SchwartzianKV(E e, SORTKEY sortkey){
        this.e = e;
        this.sortkey = sortkey;
    }

    public static <E, SORTKEY implements Comparable<SORTKEY>> 
    Function<E, SchwartzianKV<E, SORTKEY>> transformer( Function<E, SORTKEY> fn ) {
       return new Function<E, SchwartzianKV<E,SORTKEY>>() {
           @Override SchwartzianKV<E,SORTKEY> apply(E e) {
               return new SchwartzianKV<>(e, fn.apply(e));
           } 
       }
    }

    public int compare(With<E> other) {
       return sortkey.compare(other.sortkey);
    }
}
SchwartzianKV级
实现可比性{
公开期末考试E;
公开最终SORTKEY SORTKEY;
SchwartzianKV(E、E、SORTKEY、SORTKEY){
这个。e=e;
this.sortkey=sortkey;
}
公共静电
功能变压器(功能fn){
返回新函数(){
@超控施瓦茨电压应用(E){
返回新的SchwartzianKV(e,fn.apply(e));
} 
}
}
公共整数比较(与其他整数比较){
返回sortkey.compare(其他.sortkey);
}
}
现在您可以将流编写为

 Optional<E> minValue = list.stream()
                            .map( SchwartianKV.transformer( e -> f(e) ) )
                            .min()
                            .map( kv -> kv.e )
可选minValue=list.stream()
.map(千伏变压器(e->f(e)))
.min()
.图(千伏->千伏电气)
非常简洁。

list.stream()
list.stream()
    .map(e -> new AbstractMap.SimpleImmutableEntry<>(e,f(e)))
    .min(Map.Entry.comparingByValue())
    .map(Map.Entry::getKey)
.map(e->new AbstractMap.SimpleImmutableEntry(e,f(e))) .min(Map.Entry.comparingByValue()) .map(map.Entry::getKey)

基本上使用了
AbstractMap.SimpleImmutableEntry
来代替问题中的
和f
。这不是
Map.Entry的预期用途。Entry
如此不理想。

那么为什么不直接替换
.Collector(collector.toMap(Function.identity(),E::f).entrySet().stream()
新的SimpleEntry(E,f(E)))
?@tennenrishin我在Java 8 API中看不到
SimpleEntry
类。你能给我指一个参考吗?这肯定是更简单的方法(或者使用标准库中的
)。这样创建一个完整的中间集合有点难看。@MichaelAnderson是的,我同意。如果Java库有一种简单的方法来创建一个简单的对就好了,因为这就是这里所需要的。我尝试了一种解决方案,为每个条目创建一个包含两个项的列表,但这更难看。@sprint
import Java.util.AbstractMap.SimpleEntry;
这可能是“正确的”是的,但对我来说,这就像用大锤杀死蚂蚁一样。+1作为参考和实现<代码>Compariable
-非常有意义。@Tennershin我同意,但这比其他选项更易于重用。因此,如果您多次这样做,我会使用它,否则其他选项可能更适合。
list.stream()
    .map(e -> new AbstractMap.SimpleImmutableEntry<>(e,f(e)))
    .min(Map.Entry.comparingByValue())
    .map(Map.Entry::getKey)