Java 8 – Stream Collectors groupingBy examples
In this article, we will show you how to use Java 8 Stream Collectors
to group by, count, sum and sort a List
.
1. Group By, Count and Sort
1.1 Group by a List
and display the total count of it.
Java8Example1.java
package com.mkyong.java8;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Java8Example1 {
public static void main(String[] args) {
//3 apple, 2 banana, others 1
List<String> items =
Arrays.asList("apple", "apple", "banana",
"apple", "orange", "banana", "papaya");
Map<String, Long> result =
items.stream().collect(
Collectors.groupingBy(
Function.identity(), Collectors.counting()
)
);
System.out.println(result);
}
}
output
{ papaya=1, orange=1, banana=2, apple=3 }
1.2 Add sorting.
Java8Example2.java
package com.mkyong.java8;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Java8Example2 {
public static void main(String[] args) {
//3 apple, 2 banana, others 1
List<String> items =
Arrays.asList("apple", "apple", "banana",
"apple", "orange", "banana", "papaya");
Map<String, Long> result =
items.stream().collect(
Collectors.groupingBy(
Function.identity(), Collectors.counting()
)
);
Map<String, Long> finalMap = new LinkedHashMap<>();
//Sort a map and add to finalMap
result.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue()
.reversed()).forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
System.out.println(finalMap);
}
}
output
{ apple=3, banana=2, papaya=1, orange=1 }
2. List Objects
Examples to ‘group by’ a list of user defined Objects.
2.1 A Pojo.
Item.java
package com.mkyong.java8;
import java.math.BigDecimal;
public class Item {
private String name;
private int qty;
private BigDecimal price;
//constructors, getter/setters
}
2.2 Group by the name + Count or Sum the Qty.
Java8Examples3.java
package com.mkyong.java8;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Java8Examples3 {
public static void main(String[] args) {
//3 apple, 2 banana, others 1
List<Item> items = Arrays.asList(
new Item("apple", 10, new BigDecimal("9.99")),
new Item("banana", 20, new BigDecimal("19.99")),
new Item("orang", 10, new BigDecimal("29.99")),
new Item("watermelon", 10, new BigDecimal("29.99")),
new Item("papaya", 20, new BigDecimal("9.99")),
new Item("apple", 10, new BigDecimal("9.99")),
new Item("banana", 10, new BigDecimal("19.99")),
new Item("apple", 20, new BigDecimal("9.99"))
);
Map<String, Long> counting = items.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.counting()));
System.out.println(counting);
Map<String, Integer> sum = items.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.summingInt(Item::getQty)));
System.out.println(sum);
}
}
output
//Group by + Count { papaya=1, banana=2, apple=3, orang=1, watermelon=1 } //Group by + Sum qty { papaya=20, banana=30, apple=40, orang=10, watermelon=10 }
2.2 Group by Price – Collectors.groupingBy
and Collectors.mapping
example.
Java8Examples4.java
package com.mkyong.java8;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class Java8Examples4 {
public static void main(String[] args) {
//3 apple, 2 banana, others 1
List<Item> items = Arrays.asList(
new Item("apple", 10, new BigDecimal("9.99")),
new Item("banana", 20, new BigDecimal("19.99")),
new Item("orang", 10, new BigDecimal("29.99")),
new Item("watermelon", 10, new BigDecimal("29.99")),
new Item("papaya", 20, new BigDecimal("9.99")),
new Item("apple", 10, new BigDecimal("9.99")),
new Item("banana", 10, new BigDecimal("19.99")),
new Item("apple", 20, new BigDecimal("9.99"))
);
//group by price
Map<BigDecimal, List<Item>> groupByPriceMap =
items.stream().collect(Collectors.groupingBy(Item::getPrice));
System.out.println(groupByPriceMap);
// group by price, uses 'mapping' to convert List<Item> to Set<String>
Map<BigDecimal, Set<String>> result =
items.stream().collect(
Collectors.groupingBy(Item::getPrice,
Collectors.mapping(Item::getName, Collectors.toSet())
)
);
System.out.println(result);
}
}
output
{ 19.99=[ Item{name='banana', qty=20, price=19.99}, Item{name='banana', qty=10, price=19.99} ], 29.99=[ Item{name='orang', qty=10, price=29.99}, Item{name='watermelon', qty=10, price=29.99} ], 9.99=[ Item{name='apple', qty=10, price=9.99}, Item{name='papaya', qty=20, price=9.99}, Item{name='apple', qty=10, price=9.99}, Item{name='apple', qty=20, price=9.99} ] } //group by + mapping to Set { 19.99=[banana], 29.99=[orang, watermelon], 9.99=[papaya, apple] }
Greate information!!!
Thanks, good examples
Nice set of examples. Thank you!
good examples for beginners
What about doing the same example, but grouping by item name and summing the BigDecimal amounts?
Map<String, Double> result = items.stream()
.collect(Collectors.groupingBy(Item::getName, Collectors.summingDouble(i -> i.getPrice().doubleValue())));
can you give the full code please
Good 😉
Why is a LinkedHashMap being used for the sort?
Ah it’s because a LHM preserves insertion order.
Good information
Good solutions! Thanks!
loved it! thanks
Hello,
I am trying to learn functional programming in java. Below is my code
LambdaExperiments.java
package com.practice.functionalprogramming;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
import java.util.stream.Collectors;
class Employee {
private int salary;
private String name;
private int age;
public Employee(int salary, String name, int age) {
super();
this.salary = salary;
this.name = name;
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return “Employee [salary=” + salary + “, name=” + name + “, age=” + age
+ “]”;
}
}
public class LambdaExperiments {
public static void main(String[] args) {
Employee e1 = new Employee(1000, “Emp1”, 23);
Employee e2 = new Employee(500, “Emp2”, 24);
Employee e3 = new Employee(10000, “Emp3”, 27);
Employee e4 = new Employee(100, “Emp4”, 20);
Employee e5 = new Employee(15000, “Emp5”, 21);
Employee e6 = new Employee(10050, “Emp6”, 30);
List<Employee> listEmp = new ArrayList<Employee>();
listEmp.add(e1);listEmp.add(e2);
listEmp.add(e3);listEmp.add(e4);
listEmp.add(e5);listEmp.add(e6);
Stream<Employee> stream = listEmp.stream();
int sum = stream.collect(Collectors.summingInt(Employee::getSalary));
}
}
However I am getting compilation error
”
Exception in thread “main” java.lang.Error: Unresolved compilation problems:
Employee cannot be resolved to a variable
Syntax error on tokens, delete these tokens
”
I have recently updated from jdk 6 to 8.Please provide some pointers!
if a variable say unresolved , you need to import that POJO in main class
Exceptionally well explained and demonstratd
In exp: “2.2 Group by Price”
The output: “19.99” -> “29.99” -> “9.99”
As you can see, the list has been added like “9.99” -> “19.99” -> “29.99”
How to arrange output list like input?
Can I achive like – https://stackoverflow.com/questions/59876881/transform-query-results-into-different-format using anything above ? Would you please asssssist me????
Not interesting. Very easy simple tasks. Make at least sum of BigDecimals. 🙁
Map<String, BigDecimal> sumP = items.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.reducing(BigDecimal.ZERO ,
(Item a)-> a.getPrice() , (a, b) -> a.add(b))));
In the example 2.1,
Map counting = items.stream().collect(
Collectors.groupingBy(Item::getName, Collectors.counting()));
//In this above line (Item::getName) ,how its working because non static method called directly using Class Name
great, these examples saved my time. thanx.
HI I have a list with 24 elements and I want to group them 4 individual lists with each list having 6 elements. how can i do it.
Hi Raja sekhar,
The below is the logic:
List list = new ArrayList();
list.add(“abc”);
list.add(“aaa”);
list.add(“bbb”);
list.add(“ccc”);
list.add(“ddd”);
list.add(“eee”);
list.add(“fff”);
list.add(“ggg”);
List list1 = list.subList(0, 2);
List list2 = list.subList(2, 4);
List list3 = list.subList(4, 6);
List list4 = list.subList(6, 8);
System.out.println(list1);
System.out.println(list2);
System.out.println(list3);
System.out.println(list4);
Hi, is very nice information, thanks for sharing. I would like to know how could be the best way to sort a map by the order of insertion of values from ArrayList? For example:
Here the list with the correct order of values
List list = new ArrayList();
list.add(“DELETE”);
list.add(“ADD”);
list.add(“CHANGE”);
and the insertion order map:
Map m = new HashMap();
m.put(“CHANGE”,”Attr1″);
m.put(“ADD”,”Attr2″);
m.put(“DELETE”,”Attr3″);
m.put(“CHANGE”,”Attr4″);
The expected result is as follow:
DELETE=Attr3,ADD=Attr2,CHANGE=Attr4
How can I apply the sort in the map taking as source the values of the list?
I hope be clear in my question. Thanks a lot
Very nice expatiation by examples.. it help well for beginners..Thank you
the last example is grouped by price, but is not sorted by increasing price, but literal. I have e three level grouped map, and i need to sort the middle level which has the key as float. How can i do it?
Thank you!
do you have the full examples in Github?
thanks, very helpfull
1.2 Should avoid using mutable variables like finalMap.
Very good explanation..Thank you
Is there a way to check grouping based on a set.
Eg. If there is a Set with Apple, banana, Orange, Papaya and if the ArrayList doesn’t have an apple is there a way to use Stream and grouping to get result like below
//Group by + Count
{
papaya=1, banana=2, apple=0, orange=1, watermelon=1//
}
Thanks!
In the example 1.2 above, the collection has to be sorted by key as well:
//Sort a map and add to finalMap
result.entrySet().stream()
.sorted(Map.Entry.comparingByValue()
.reversed()).sorted(Map.Entry.comparingByKey()).
forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
The resulting output is
{apple=3, banana=2, orange=1, papaya=1}
Thanks
Why do we need forEachOrdered here? Cause we use sequential stream.