Aggregate function on list in Java
I have a list of Java objects and I need to reduce it to apply aggregate functions, such as through database selection
Note: data is calculated from multiple databases and service calls I want thousands of rows, and each row will always have the same number of "cells" This quantity varies between executions
Sample:
Assuming that my data is represented in the object list [3] (list < object [] >), my data may be:
[{"A","X",1},{"A","Y",5},{"B",2}]
Sample 1:
Sum index 2, grouped by indexes 0 and 1
[{"A",3}]
Sample 2:
Max exceeds index 2, grouped by index 0
[{"A",2}]
Does anyone know any frameworks or APIs that can simulate this behavior in Java?
My first choice is to insert all data into no SQL database (such as couchbase), then apply map reduce, and finally get the results But this solution has a lot of overhead
My second option is to embed a groovy script, but it also has a lot of overhead
Solution
If Java 8 is an option, you can use stream Collect to achieve what you want
For example:
import static java.util.stream.Collectors.*; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; public class Example { public static void main(String[] args) { List<List<Object>> list = Arrays.asList( Arrays.<Object>asList("A",1),Arrays.<Object>asList("A",5),Arrays.<Object>asList("B",2) ); Map<Set<Object>,List<List<Object>>> groups = list.stream() .collect(groupingBy(Example::newGroup)); System.out.println(groups); Map<Set<Object>,Integer> sums = list.stream() .collect(groupingBy(Example::newGroup,summingInt(Example::getInt))); System.out.println(sums); Map<Set<Object>,Optional<List<Object>>> max = list.stream() .collect(groupingBy(Example::newGroup,maxBy(Example::compare))); System.out.println(max); } private static Set<Object> newGroup(List<Object> item) { return new HashSet<>(Arrays.asList(item.get(0),item.get(1))); } private static Integer getInt(List<Object> items) { return (Integer)items.get(2); } private static int compare(List<Object> items1,List<Object> items2) { return (((Integer)items1.get(2)) - ((Integer)items2.get(2))); } }
The following outputs are given:
{[A,X]=[[A,X,1]],[B,X]=[[B,1],2]],[A,Y]=[[A,Y,5]]} {[A,X]=1,X]=3,Y]=5} {[A,X]=Optional[[A,X]=Optional[[B,Y]=Optional[[A,5]]}
Alternatively, using the Java 8 example as inspiration, although it is more lengthy, you can implement the same functions in the old version of Java:
import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class Example { public static void main(String[] args) { List<List<Object>> list = Arrays.asList( Arrays.<Object>asList("A",2) ); Function<List<Object>,Set<Object>> groupBy = new Function<List<Object>,Set<Object>>() { @Override public Set<Object> apply(List<Object> item) { return new HashSet<>(Arrays.asList(item.get(0),item.get(1))); } }; Map<Set<Object>,List<List<Object>>> groups = group( list,groupBy ); System.out.println(groups); Map<Set<Object>,Integer> sums = sum( list,groupBy,new Function<List<Object>,Integer>() { @Override public Integer apply(List<Object> item) { return (Integer)item.get(2); } } ); System.out.println(sums); Map<Set<Object>,List<Object>> max = max( list,new Comparator<List<Object>>() { @Override public int compare(List<Object> items1,List<Object> items2) { return (((Integer)items1.get(2)) - ((Integer)items2.get(2))); } } ); System.out.println(max); } public static <K,V> Map<K,List<V>> group(Collection<V> items,Function<V,K> groupFunction) { Map<K,List<V>> groupedItems = new HashMap<>(); for (V item : items) { K key = groupFunction.apply(item); List<V> itemGroup = groupedItems.get(key); if (itemGroup == null) { itemGroup = new ArrayList<>(); groupedItems.put(key,itemGroup); } itemGroup.add(item); } return groupedItems; } public static <K,Integer> sum(Collection<V> items,K> groupFunction,Integer> intGetter) { Map<K,Integer> sums = new HashMap<>(); for (V item : items) { K key = groupFunction.apply(item); Integer sum = sums.get(key); sums.put(key,sum != null ? sum + intGetter.apply(item) : intGetter.apply(item)); } return sums; } public static <K,V> max(Collection<V> items,Comparator<V> comparator) { Map<K,V> maximums = new HashMap<>(); for (V item : items) { K key = groupFunction.apply(item); V maximum = maximums.get(key); if (maximum == null || comparator.compare(maximum,item) < 0) { maximums.put(key,item); } } return maximums; } private static interface Function<T,R> { public R apply(T value); } }
The following outputs are given:
{[A,5]],2]]} {[A,Y]=5,X]=3} {[A,X]=[A,Y]=[A,5],X]=[B,2]}