Ich habe ein Objekt Prozess, der ein Datum und einen booleschen Fehler Indikator hat. Ich möchte für jedes Datum eine Zählung der Gesamtprozesse und eine Anzahl der Prozesse mit Fehlern erhalten. So wird zum Beispiel Jun 01 Zählungen 2, 1; Jun 02 wird 1, 0 und Jun 03 1, 1 haben. Der einzige Weg, wie ich das geschafft habe, ist zweimal zu streamen, um die Zählungen zu bekommen. Ich habe versucht, einen benutzerdefinierten Collector zu implementieren, war aber nicht erfolgreich. Gibt es eine elegante Lösung anstelle meiner kludgy-Methode?Java 8 Streams groupby und zählen mehrere Eigenschaften
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
final List<Process> processes = new ArrayList<>();
processes.add(new Process(sdf.parse("2016-06-01"), false));
processes.add(new Process(sdf.parse("2016-06-01"), true));
processes.add(new Process(sdf.parse("2016-06-02"), false));
processes.add(new Process(sdf.parse("2016-06-03"), true));
System.out.println(processes.stream()
.collect(
Collectors.groupingBy(Process::getDate, Collectors.counting())));
System.out.println(processes.stream().filter(order -> order.isHasError())
.collect(
Collectors.groupingBy(Process::getDate, Collectors.counting())));
private class Process {
private Date date;
private boolean hasError;
public Process(Date date, boolean hasError) {
this.date = date;
this.hasError = hasError;
}
public Date getDate() {
return date;
}
public boolean isHasError() {
return hasError;
}
}
-Code nach @ glee8e-Lösung und @ Holger Tipps
Collector<Process, Result, Result> ProcessCollector = Collector.of(
() -> Result::new,
(r, p) -> {
r.increment(0);
if (p.isHasError()) {
r.increment(1);
}
}, (r1, r2) -> {
r1.add(0, r2.get(0));
r1.add(1, r2.get(1));
return r1;
});
Map<Date, Result> results = Processs.stream().collect(groupingBy(Process::getDate, ProcessCollector));
results.entrySet().stream().sorted(Comparator.comparing(Entry::getKey)).forEach(entry -> System.out
.println(String.format("date = %s, %s", sdf.format(entry.getKey()), entry.getValue())));
private class Result {
private AtomicIntegerArray array = new AtomicIntegerArray(2);
public int get(int index) {
return array.get(index);
}
public void increment(int index) {
array.getAndIncrement(index);
}
public void add(int index, int delta) {
array.addAndGet(index, delta);
}
@Override
public String toString() {
return String.format("totalProcesses = %d, totalErrors = %d", array.get(0), array.get(1));
}
}
haben, können Sie auch die Art von 'list' schwächen zu' Collection' auf Ihrer zweiten Zeile. – bphilipnyc