4

Is there a way to create multiple maps from a list in Java 8 using stream or other way?

I have a list of custom object. Suppose List where Employee has departmentId so there are some employees which have the same departmentId = "001" for example. I want to create multiple maps based on Employee.departmentId.

For example,

map1 = <"001", employee1>,<"001", employee3>, <"001", employee8>...<"001", employee100>

map2 = <"002", employee2>,<"002", employee4>,..., <"002", employee8> ... something like this.

since for each element in list check the departmentId and put it in corresponding map by using old for loop. Wondering is there a better way to do this? Currently I'm using Java 8

6
  • 7
    Why don't you use a Map<String,List<Employee>>? Commented Nov 21, 2019 at 18:54
  • 2
    You can't create a map with duplicate keys. Commented Nov 21, 2019 at 19:06
  • Sounds like a possible application of a groupingBy collector of java streams, e.g. like done here Commented Nov 21, 2019 at 19:11
  • i have mentioned on my answere some of alternative libraries you can use to achieve what you want but none of the existing Java core Map implementations allow a Map to handle multiple values for a single key. Commented Nov 21, 2019 at 21:38
  • Are you just trying to create a Map<String,Map<String,Employee>> ? Commented Nov 22, 2019 at 3:20

3 Answers 3

3

As has been suggested, using a Map<String,List<Employee>> is probably what you want. I constructed a small class and an example to illustrate the process.

      List<Employee> emps = List.of(
            new Employee("001", "Jim"),
            new Employee("002", "Bob"),
            new Employee("001", "June"),
            new Employee("002", "Jean"));

     // For each employee, using departmentId as the key, construct
     // a map containing lists of all employees that have that ID

      Map<String, List<Employee>> empMap = 
          emps
              .stream()
              .collect(
                  Collectors.groupingBy(emp -> emp.departmentId)
              );

      for (Entry<?, ?> e : empMap.entrySet()) {
         System.out.println(e.getKey() + "-->" + e.getValue());
      }



      class Employee {
          public String departmentId;
          public String name;
    
          public Employee(String departmentId, String name) {
             this.departmentId = departmentId;
             this.name = name;
          }
          public String toString() {
             return "(" + departmentId + " " + name + ")";
          }
       }

This displays

001-->[(001 Jim), (001 June)]
002-->[(002 Bob), (002 Jean)]

Another option, which would do the exact same thing is as follows:

This creates an empty map. Then it iterates over the list of employees and computes whether the value for the key exists. If it does, it returns the list and adds the entry to that list. If it doesn't, it then creates the new ArrayList and then adds the employee for that list, storing the list in the provided key.

     Map<String, List<Employee>> emp2 = new HashMap<>();
         for (Employee emp : emps) {
            emp2.compute(emp.departmentId,
               (ID, list) -> list == null ? new ArrayList<>()
                     : list).add(emp);
      }

In this case my preference would be the first method.

Sign up to request clarification or add additional context in comments.

Comments

0

It is not possible to do this. Because Map can not have duplicate key. You can create Map<String,List<Employee>> by using Collectors.groupingBy()

Comments

0

none of the existing Java core Map implementations allow a Map to handle multiple values for a single key.

if we try to insert two values for the same key, the second value will be stored, while the first one will be dropped.

Map<String, String> map = new HashMap<>();
assertThat(map.put("key1", "value1")).isEqualTo(null);
assertThat(map.put("key1", "value2")).isEqualTo("value1");
assertThat(map.get("key1")).isEqualTo("value2");

you can achieve what you want by using Collection as Value here is a simple example :

using java version < 8

Map<String, List<String>> map = new HashMap<>();
List<String> list = new ArrayList<>();
map.put("key1", list);
map.get("key1").add("value1");
map.get("key1").add("value2");

assertThat(map.get("key1").get(0)).isEqualTo("value1");
assertThat(map.get("key1").get(1)).isEqualTo("value2");

using java version > 8

Map<String, List<String>> map = new HashMap<>();
map.computeIfAbsent("key1", k -> new ArrayList<>()).add("value1");
map.computeIfAbsent("key1", k -> new ArrayList<>()).add("value2");

assertThat(map.get("key1").get(0)).isEqualTo("value1");
assertThat(map.get("key1").get(1)).isEqualTo("value2");

what you want exactly you can achieve it by using Apache Library !

Solution : add Maven or jar

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-collections4</artifactId>
  <version>4.1</version>
</dependency>

then :

MultiValuedMap<String, Employe> map = new ArrayListValuedHashMap<>();
map.put("key1", new Employe("blahblah"));
map.put("key1", new Employe("blahblah"));
map.put("key1", new Employe("blahblah"));

Other alternatives libraries : Guava Multimap
Link : https://guava.dev/releases/23.0/api/docs/com/google/common/collect/Multimap.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.