I often find myself doing something like this:
list.stream().min(new Comparator<>() {
@Override
public int compare(E a, E b) {
return Double.compare(f(a),f(b));
}
})
where f
is a computation intensive function. This requires twice as many evaluations of f
as are actually necessary. I'd prefer to
list.stream().mapToDouble(f).min()
but then I don't know how to get the original element that this minimum corresponds to.
One ugly way around this is
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;
}
}
and then
list.stream().map(e -> new WithF<>(e,f(e))).min(Comparator.comparingDouble(WithF::getFE))
Is there a better, idiomatic way of doing this thing with the stream API?
This transformation is often called the Schwartzian Transform
I'd actually generalize WithF
with a few extra bits, and rename it to make the pipe neater.
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);
}
}
Now you can write the stream as
Optional<E> minValue = list.stream()
.map( SchwartianKV.transformer( e -> f(e) ) )
.min()
.map( kv -> kv.e )
Which is pretty concise.
While waiting I'll post what I'm currently considering:
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With