I'm trying to leverage the Collectors.Stream() library to do various data aggregation and manipulation. Right now my data set can range anywhere between a couple thousand records to a couple of million.
Let's say that we have the below POJO class:
public class Item{
String name;
Double quantity;
Double price;
Double totalDollarAmount;
public Item(String name, Double quantity, Double price) {
this.name = name;
this.quantity= quantity;
this.price = price;
}
//Basic Getters and setters
public Double getTotalDollarAmount(){
return getQuantity()*getPrice();
}
}
From a List<Item>
I want to be able to quickly calculate how many of each item I've bought, the average price, and the total money spent for that item(s). Let's say for this scenario I have the following list:
List<Item> itemsOnly = Arrays.asList(
new Item("apple", 10.0, 9.99),
new Item("banana", 20.0, 19.99),
new Item("orange", 10.0, 29.99),
new Item("watermelon", 10.0, 29.99),
new Item("papaya", 20.0, 9.99),
new Item("apple", 100.0, 9.99),
new Item("apple", 20.0, 9.99)
);
If I want to get the total quantity, average price, and total dollar amount of each unique item in that list I can do this:
System.out.println("Total Quantity for each Item: " + itemsOnly.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.summingDouble(Item::getQuantity))));
System.out.println("Average Price for each Item: " + itemsOnly.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.averagingDouble(Item::getPrice))));
System.out.println("Total Dollar Amount for each Item: " + itemsOnly.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.summingDouble(Item::getTotalDollarAmount))));
This would return the following:
Total Quantity for each Item: {papaya=20.0, orange=10.0, banana=20.0, apple=130.0, watermelon=10.0}
Average Price for each Item: {papaya=9.99, orange=29.99, banana=19.99, apple=9.99, watermelon=29.99}
Total Dollar Amount for each Item: {papaya=199.8, orange=299.9, banana=399.79999999999995, apple=1298.7, watermelon=299.9}
Now, what I want to do is store each of those values into a new Item
object.
In the above example I would have a new object that would have the name set to "apple", the quantity = 130.0, price = 9.99, and total dollar amount = 1298.7.
I'd like to be able to create this new Item
without doing a loop through a list of item names that I want and calling a getter on three different maps (quantity, average price, total amount). I'm not sure if this is possible, but ideally I'd be able to get a map where the key is the name of the item and the value is a fully defined class of Item
, like Map<String,Item>
.
Is there any way to do this using Collectors stream? Is there a better way to do fast aggregation over a large data set in Java?