Penso che mentre il max
/min
sia unico, questo non è ovviamente garantito per lo argMax
/argMin
; ciò in particolare implica che il tipo di riduzione debba essere una raccolta, come ad esempio uno List
. Ciò richiede un po 'più di lavoro di quanto suggerito sopra.
La seguente classe ArgMaxCollector<T>
fornisce una semplice implementazione di tale riduzione. Il main
mostra un'applicazione di tale classe per calcolare la argMax
/argMin
del set di stringhe
one two three four five six seven
ordinati per la loro lunghezza. L'uscita (comunicazione dei risultati delle argMax
e argMin
collettori rispettivamente) dovrebbe essere
[three, seven]
[one, two, six]
che sono le due e le tre corde breve Più lungo rispettivamente.
Questo è il mio primo tentativo di utilizzare le nuove API di flusso Java 8, quindi qualsiasi commento sarà più che benvenuto!
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collector;
class ArgMaxCollector<T> {
private T max = null;
private ArrayList<T> argMax = new ArrayList<T>();
private Comparator<? super T> comparator;
private ArgMaxCollector(Comparator<? super T> comparator) {
this.comparator = comparator;
}
public void accept(T element) {
int cmp = max == null ? -1 : comparator.compare(max, element);
if (cmp < 0) {
max = element;
argMax.clear();
argMax.add(element);
} else if (cmp == 0)
argMax.add(element);
}
public void combine(ArgMaxCollector<T> other) {
int cmp = comparator.compare(max, other.max);
if (cmp < 0) {
max = other.max;
argMax = other.argMax;
} else if (cmp == 0) {
argMax.addAll(other.argMax);
}
}
public List<T> get() {
return argMax;
}
public static <T> Collector<T, ArgMaxCollector<T>, List<T>> collector(Comparator<? super T> comparator) {
return Collector.of(
() -> new ArgMaxCollector<T>(comparator),
(a, b) -> a.accept(b),
(a, b) ->{ a.combine(b); return a; },
a -> a.get()
);
}
}
public class ArgMax {
public static void main(String[] args) {
List<String> names = Arrays.asList(new String[] { "one", "two", "three", "four", "five", "six", "seven" });
Collector<String, ArgMaxCollector<String>, List<String>> argMax = ArgMaxCollector.collector(Comparator.comparing(String::length));
Collector<String, ArgMaxCollector<String>, List<String>> argMin = ArgMaxCollector.collector(Comparator.comparing(String::length).reversed());
System.out.println(names.stream().collect(argMax));
System.out.println(names.stream().collect(argMin));
}
}
Gah! Non utilizzare raw 'get()' alla fine, altrimenti lanci NSEE se lo stream è vuoto. Utilizza un metodo sicuro come 'orElse',' orElseThrow' o 'ifPresent'. –
@BrianGoetz Penso che abbiamo scoperto una delle allergie di Brian. Starnutisce ogni volta che scrivo anche 'Optional.get()'. –
@StuartMarks Effettivamente così. Non avremmo mai dovuto chiamarlo 'get'. Avremmo dovuto chiamarlo 'getOrThrow()' o 'orElseThrow()' o 'getUnsafely()' o probabilmente solo 'getOrThrowNoSuchElementExcpetionIfThisOptionalIsNotPresent()'. –