在流中找到与地图后最小值对应的预映射元素

Mus*_*ful 7 java reduce

我经常发现自己这样做:

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

    @Override
    public int compare(E a, E b) {
        return Double.compare(f(a),f(b));
    }
})
Run Code Online (Sandbox Code Playgroud)

哪里f是计算密集型功能.这需要两倍于f实际需要的评估.我更喜欢

list.stream().mapToDouble(f).min()
Run Code Online (Sandbox Code Playgroud)

但后来我不知道如何获得这个最小值对应的原始元素.

围绕这个的一个丑陋的方法是

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后

list.stream().map(e -> new WithF<>(e,f(e))).min(Comparator.comparingDouble(WithF::getFE))
Run Code Online (Sandbox Code Playgroud)

使用流API是否有更好的,惯用的方法?

Mic*_*son 2

这种变换通常称为施瓦茨变换

实际上,我会WithF用一些额外的位进行概括,并将其重命名以使管道更整洁。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以将流写为

 Optional<E> minValue = list.stream()
                            .map( SchwartianKV.transformer( e -> f(e) ) )
                            .min()
                            .map( kv -> kv.e )
Run Code Online (Sandbox Code Playgroud)

这非常简洁。