18

I have a class like this

ObjectA id type 

where id is unique but the type can be duplicate so if I have a list of ObjectA like this

(id, type) = (1, "A") , (2, "B"), (3, "C"), (4, "A") 

then I want Map<type, List<id>> where map is

< "A",[1,4], "B",[2], "C",[3] > 

It is working with Java 7 but can't find a way to do it in Java 8. In Java 8 I can create key, value pair but not able to create a list if a type is same.

2
  • 1
    which code is working with java 7? Commented Feb 12, 2018 at 13:25
  • Please post the code causing the problem? Commented Feb 12, 2018 at 13:25

6 Answers 6

24
yourTypes.stream() .collect(Collectors.groupingBy( ObjectA::getType, Collectors.mapping( ObjectA::getId, Collectors.toList() ))) 
Sign up to request clarification or add additional context in comments.

Comments

20

Employee list to map

List<Employee> list = new ArrayList<>(); list.add(new Employee(1, "John",80000)); list.add(new Employee(2, "Jack", 90000)); list.add(new Employee(3, "Ricky", 120000)); // key = id, value - name Map<Integer, String> result1 = list.stream().collect( Collectors.toMap(Employee::getId, Employee::getName)); 

2 Comments

What if I want to give a constant value instead of Employee::getName?
Map<Integer, String> result1 = list.stream().collect( Collectors.toMap(Employee::getId, "constant value here like this")); @ArunGowda
7

Though you got some nice answer. I would like to share another way of doing same. It's when you have to tackle really complex conversions to map.

class Student { private String name; private Integer id; //getters / setters / constructors } Map<String, List<Integer>> map = Arrays.asList( new Student("Jack", 2), new Student("Jack", 2), new Student("Moira", 4) ) .stream() .collect( Collectors.toMap( Student::getName, student -> { List list = new ArrayList<Integer>(); list.add(student.getId()); return list; }, (s, a) -> { s.add(a.get(0)); return s; } ) ); 

Notice how complex you could play with value and return the new value accordingly.

toMap parameters are respectively keyMapper function, valueMapper function and merger respectively.

Cheers!

Comments

4

A way to do it without streams:

Map<String, List<Integer>> map = new HashMap<>(); list.forEach(object -> map.computeIfAbsent(object.getType(), k -> new ArrayList<>()) .add(object.getId())); 

This uses Iterable.forEach and Map.computeIfAbsent to iterate the list and group its elements (here named object) by its type attribute, creating a new ArrayList if there was no entry for that type in the map yet. Then, the id of the object is added to the list.

3 Comments

without streams is going to be your nick soon... :)
I disagree! I found computeIfAbsent wonderful when it was beyond streams to tackle some scenario.
Perfect! that is exctly what i was looking for, even without stream is a great answer, thannk you
3
List<Employee> list = new ArrayList<>(); list.add(new Employee(1, "John",80000)); list.add(new Employee(2, "Jack", 90000)); list.add(new Employee(3, "Ricky", 120000)); // key = id, value - name Map<Integer, String> result = list.stream().collect( Collectors.toMap(Employee::getId, Employee::getName)); If you want to give a constant value instead of name: // key = id, value - "ABC" Map<Integer, String> result = list.stream().collect( Collectors.toMap(Employee::getId, emp-> "ABC")); 

1 Comment

Please provide a detailed explanation to your answer, in order for the next user to understand your answer better.
0

List to Map object

employeeList.stream().collect(Collectors.groupingBy(Employee::getName, Collectors.toList())) .forEach((key,value)->System.out.println("key : "+key+" , value : "+value));

output:

key: Name : value : List of employee Object

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.