List aggregation in Java (Collectors.groupingBy)

You can use Collectors.groupingBy to group Lists and get Map type data of Key-List. I have put together a practical sample code.

Target object

public class Product {

	private String productId;

	private String productName;

	private String productType;

	private BigDecimal price;
	
	private long qty;

	// getter setter

Create a List with the following image using the above object.

1 productName:iPhone X        productType:iPhone    price:120000   qty:2
2 productName:iPhone 8 Plus   productType:iPhone    price:110000   qty:3
3 productName:iPhone 8        productType:iPhone    price:100000   qty:1
4 productName:Galaxy S9       productType:Android   price:100000   qty:4
5 productName:Galaxy S9 plus  productType:Android   price:110000   qty:3
6 productName:Windows phone   productType:Others    price:80000    qty:1
7 productName:Windows phone   productType:Others    price:85000    qty:2

Single item grouping

Group single items with Collectors.groupingBy.

//Single item grouping
Map<String, List<Product>> grpByType = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType));

Execution result:

{iPhone=[productId:001 productName:iPhone X productType:iPhone price:120000 qty:2, productId:002 productName:iPhone 8 Plus productType:iPhone price:110000 qty:3, productId:003 productName:iPhone 8 productType:iPhone price:100000 qty:1], 
 Others=[productId:006 productName:Windows phone productType:Others price:80000 qty:1, productId:007 productName:Windows phone productType:Others price:85000 qty:2], 
 Android=[productId:004 productName:Galaxy S9 productType:Android price:100000 qty:4, productId:005 productName:Galaxy S9 plus productType:Android price:110000 qty:3]}

Grouping of multiple items

Method 1

Create a composite key in advance and use that composite key when grouping.

//Create a composite key
Function<Product, String> compositeKey = prd -> {
	StringBuffer sb = new StringBuffer();
	sb.append(prd.getProductType()).append("-").append(prd.getProductName());
	return sb.toString();
};

//Grouping with compound keys
Map<String, List<Product>> grpByComplexKeys = prdList.stream().collect(
				Collectors.groupingBy(compositeKey));

Execution result:

{iPhone-iPhone 8 Plus=[productId:002 productName:iPhone 8 Plus productType:iPhone price:110000 qty:3], 
 Android-Galaxy S9 plus=[productId:005 productName:Galaxy S9 plus productType:Android price:110000 qty:3], 
 Others-Windows phone=[productId:006 productName:Windows phone productType:Others price:80000 qty:1, productId:007 productName:Windows phone productType:Others price:85000 qty:2], 
 Android-Galaxy S9=[productId:004 productName:Galaxy S9 productType:Android price:100000 qty:4], 
 iPhone-iPhone 8=[productId:003 productName:iPhone 8 productType:iPhone price:100000 qty:1], 
 iPhone-iPhone X=[productId:001 productName:iPhone X productType:iPhone price:120000 qty:2]}

Method 2

Create a composite key class and override hashCode and equals for comparison.

public class Keys {
	
	String productType;
	String productName;
	
	public Keys(String productType, String productName) {
		this.productType = productType;
		this.productName = productName;
	}

	@Override
	public int hashCode() {
		//Omitted (automatically generated from IDE)
	}

	@Override
	public boolean equals(Object obj) {
		//Omitted (automatically generated from IDE)
	}

Group by the created decryption key class.

//Grouping with compound keys
Map<Keys, List<Product>> grpByComplexKeys = prdList.stream().collect(
				Collectors.groupingBy(prd -> new Keys(prd.getProductType(), prd.getProductName())));

Execution result:

{Android-Galaxy S9 plus=[productId:005 productName:Galaxy S9 plus productType:Android price:110000 qty:3], 
 iPhone-iPhone 8 Plus=[productId:002 productName:iPhone 8 Plus productType:iPhone price:110000 qty:3], 
 Android-Galaxy S9=[productId:004 productName:Galaxy S9 productType:Android price:100000 qty:4], 
 iPhone-iPhone 8=[productId:003 productName:iPhone 8 productType:iPhone price:100000 qty:1], 
 iPhone-iPhone X=[productId:001 productName:iPhone X productType:iPhone price:120000 qty:2], 
 Others-Windows phone=[productId:006 productName:Windows phone productType:Others price:80000 qty:1, productId:007 productName:Windows phone productType:Others price:85000 qty:2]}

Grouping multiple times

//Grouping twice
Map<String, Map<String, List<Product>>> grpByTypeAndGrpByName = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType, 
					Collectors.groupingBy(Product::getProductName)));

Execution result:

{iPhone={iPhone 8=[productId:003 productName:iPhone 8 productType:iPhone price:100000 qty:1], iPhone X=[productId:001 productName:iPhone X productType:iPhone price:120000 qty:2], iPhone 8 Plus=[productId:002 productName:iPhone 8 Plus productType:iPhone price:110000 qty:3]}, 
 Others={Windows phone=[productId:006 productName:Windows phone productType:Others price:80000 qty:1, productId:007 productName:Windows phone productType:Others price:85000 qty:2]}, 
 Android={Galaxy S9=[productId:004 productName:Galaxy S9 productType:Android price:100000 qty:4], Galaxy S9 plus=[productId:005 productName:Galaxy S9 plus productType:Android price:110000 qty:3]}}

Group total

Total of int, long, etc.

Find the sum of int and long with Collectors.summingInt and Collectors.summingLong.

//INT sum
Map<String, Long> grpByTypeSumQty = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType, 
					Collectors.summingLong(Product::getQty)));

Execution result:

{iPhone=6, Others=3, Android=7}

Big Decimal total

Find the sum of Big Decimal with Collectors.reducing.

//Big Decimal total
Map<Object, BigDecimal> grpByTypeSum = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType, 
					Collectors.reducing(BigDecimal.ZERO, Product::getPrice, BigDecimal::add)));

Execution result:

{iPhone=330000, Others=165000, Android=210000}

Group maximum

Maximum value of int, long

Use Comparator.comparingInt and Comparator.comparingLong to find the maximum value of the group.

Map<String, Optional<Product>> grpByTypeMaxInt = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType, 
					Collectors.maxBy(Comparator.comparingLong(Product::getQty))));

Execution result:

{iPhone=Optional[productId:002 productName:iPhone 8 Plus productType:iPhone price:110000 qty:3], 
 Others=Optional[productId:007 productName:Windows phone productType:Others price:85000 qty:2], 
 Android=Optional[productId:004 productName:Galaxy S9 productType:Android price:100000 qty:4]}

Maximum value of Big Decimal

You can get the maximum value of the group with Comparator.comparing.

Map<String, Optional<Product>> grpByTypeMaxDecimal2 = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType, 
					Collectors.maxBy(Comparator.comparing(Product::getPrice))));

You can also use your own Comparator.

//Maximum value of Big Decimal
Map<String, Optional<Product>> grpByTypeMaxDecimal = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType, 
					Collectors.maxBy(new Comparator<Product>() {

			@Override
			public int compare(Product o1, Product o2) {
				return o1.getPrice().compareTo(o2.getPrice());
			}

		}))
);

Execution result:

{iPhone=Optional[productId:001 productName:iPhone X productType:iPhone price:120000 qty:2], 
 Others=Optional[productId:007 productName:Windows phone productType:Others price:85000 qty:2], 
 Android=Optional[productId:005 productName:Galaxy S9 plus productType:Android price:110000 qty:3]}

Complex formula

A calculation formula (unit price x quantity) is defined in advance, and the total value of the group is calculated using it.

//Calculation formula (unit price x quantity)
Function<Product, BigDecimal> calcFunction = prd -> 
				prd.getPrice().multiply(new BigDecimal(prd.getQty()));

//Aggregation
Map<String, BigDecimal> grpByTypeToSum = prdList.stream().collect(
				Collectors.groupingBy(Product::getProductType,
					Collectors.reducing(BigDecimal.ZERO, calcFunction, BigDecimal::add)));

Execution result:

{iPhone=670000, Others=250000, Android=730000}

Recommended Posts

List aggregation in Java (Collectors.groupingBy)
[java] sort in list
List of members added in Java 9
List of types added in Java 9
Partization in Java
Java memorandum (list)
Clone Java List.
Changes in Java 11
Change List <Optional <T >> to Optional <List <T >> in Java
Immutable (immutable) List object conversion function in Java8
Arrylist and linked list difference in java
Process every arbitrary number in Java List
Pi in Java
FizzBuzz in Java
About List [Java]
Do not declare variables in List in Java
Read JSON in Java
Interpreter implementation in Java
Make Blackjack in Java
Rock-paper-scissors app in Java
Constraint programming in Java
Put java8 in centos7
NVL-ish guy in Java
Combine arrays in Java
Callable Interface in Java
Comments in Java source
Azure functions in java
Format XML in Java
Simple htmlspecialchars in Java
Boyer-Moore implementation in Java
Hello World in Java
Use OpenCV in Java
webApi memorandum in java
Ping commands in Java
Various threads in java
Heapsort implementation (in java)
Zabbix API in Java
ASCII art in Java
Compare Lists in Java
POST JSON in Java
Express failure in Java
Create JSON in Java
Date manipulation in Java 8
Use PreparedStatement in Java
What's new in Java 9,10,11
[Memo] Java Linked List
Parallel execution in Java
Initializing HashMap in Java
Sample code to convert List to List <String> in Java Stream
[Java] Get the file path in the folder with List
[Java] List type / Array type conversion
Try using RocksDB in Java
Read binary files in Java 1
Avoid Yubaba's error in Java
Get EXIF information in Java
Save Java PDF in Excel
[Neta] Sleep Sort in Java
[Java, stream] Sort object list in Japanese by property name
Edit ini in Java: ini4j
Java history in this world
Let Java segfault in 6 lines