Skip to content

Instantly share code, notes, and snippets.

@spullara
Last active September 21, 2020 14:15
Show Gist options
  • Save spullara/4752663 to your computer and use it in GitHub Desktop.
Save spullara/4752663 to your computer and use it in GitHub Desktop.
JDK 8 experiment where I recreate Excel pivot tables for collections of structured objects.
@Test
public void testPivotTable() {
List<Row> rows = new ArrayList<>();
rows.add(new Row("East", "Boy", "Tee", 10, 12.00));
rows.add(new Row("East", "Boy", "Golf", 15, 20.00));
rows.add(new Row("East", "Girl", "Tee", 8, 14.00));
rows.add(new Row("East", "Girl", "Golf", 20, 24.00));
rows.add(new Row("West", "Boy", "Tee", 5, 12.00));
rows.add(new Row("West", "Boy", "Golf", 12, 20.00));
rows.add(new Row("West", "Girl", "Tee", 15, 14.00));
rows.add(new Row("West", "Girl", "Golf", 10, 24.00));
// groupBy region and gender, summing total sales
Map<String, Map<String, Double>> pivot = pivot(rows,
(r) -> r.region,
(r) -> r.gender,
(rs) -> rs.stream().map((row) -> row.price * row.units).reduce(0.0, (a, b) -> a + b));
System.out.println(pivot);
}
public static <K, V, W> Map<K, W> transformValues(Map<K, V> oldmap, Function<V, W> transform) {
return oldmap.entrySet().stream().collect(HashMap::new,
(map, entry) -> map.put(entry.getKey(), transform.apply(entry.getValue())),
Map::putAll);
}
public static <K1, K2, IN, OUT> Map<K1, Map<K2, OUT>> pivot(Collection<IN> rows, Function<IN, K1> left, Function<IN, K2> top, Function<Collection<IN>, OUT> aggregate) {
Map<K1, Collection<IN>> leftGroup = rows.stream().collect(groupingBy(left));
Map<K1, Map<K2, Collection<IN>>> grid = transformValues(leftGroup, (rs) -> rs.stream().collect(groupingBy(top)));
return transformValues(grid, (map) -> transformValues(map, aggregate));
}
@Test
public void testPivotTable() {
List<Row> rows = new ArrayList<>();
rows.add(new Row("East", "Boy", "Tee", 10, 12.00));
rows.add(new Row("East", "Boy", "Golf", 15, 20.00));
rows.add(new Row("East", "Girl", "Tee", 8, 14.00));
rows.add(new Row("East", "Girl", "Golf", 20, 24.00));
rows.add(new Row("West", "Boy", "Tee", 5, 12.00));
rows.add(new Row("West", "Boy", "Golf", 12, 20.00));
rows.add(new Row("West", "Girl", "Tee", 15, 14.00));
rows.add(new Row("West", "Girl", "Golf", 10, 24.00));
// groupBy region and gender, summing total sales
Map<String, Map<String, Double>> pivot = rows.stream().collect(groupingBy(r -> r.region,
groupingReduce(r -> r.gender, r -> r.price * r.units, Double::sum)));
System.out.println(pivot);
}
@spullara
Copy link
Author

{East={Boy=420.0, Girl=592.0}, West={Boy=300.0, Girl=450.0}}

@spullara
Copy link
Author

Turns out there is already a shortcut in the form of groupingReduce() included in the API.

@hoffrocket
Copy link

Nice! What jdk8 build is that? I tried 1.8.0-ea-b76 (latest from http://jdk8.java.net/download.html) on osx but am missing .stream()

@hoffrocket
Copy link

Ah, the builds with Stream support are here: http://jdk8.java.net/lambda/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment