How to convert List to Map?

511,320

Solution 1

List<Item> list;
Map<Key,Item> map = new HashMap<Key,Item>();
for (Item i : list) map.put(i.getKey(),i);

Assuming of course that each Item has a getKey() method that returns a key of the proper type.

Solution 2

With , you'll be able to do this in one line using streams, and the Collectors class.

Map<String, Item> map = 
    list.stream().collect(Collectors.toMap(Item::getKey, item -> item));

Short demo:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Test{
    public static void main (String [] args){
        List<Item> list = IntStream.rangeClosed(1, 4)
                                   .mapToObj(Item::new)
                                   .collect(Collectors.toList()); //[Item [i=1], Item [i=2], Item [i=3], Item [i=4]]

        Map<String, Item> map = 
            list.stream().collect(Collectors.toMap(Item::getKey, item -> item));

        map.forEach((k, v) -> System.out.println(k + " => " + v));
    }
}
class Item {

    private final int i;

    public Item(int i){
        this.i = i;
    }

    public String getKey(){
        return "Key-"+i;
    }

    @Override
    public String toString() {
        return "Item [i=" + i + "]";
    }
}

Output:

Key-1 => Item [i=1]
Key-2 => Item [i=2]
Key-3 => Item [i=3]
Key-4 => Item [i=4]

As noted in comments, you can use Function.identity() instead of item -> item, although I find i -> i rather explicit.

And to be complete note that you can use a binary operator if your function is not bijective. For example let's consider this List and the mapping function that for an int value, compute the result of it modulo 3:

List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6);
Map<String, Integer> map = 
    intList.stream().collect(toMap(i -> String.valueOf(i % 3), i -> i));

When running this code, you'll get an error saying java.lang.IllegalStateException: Duplicate key 1. This is because 1 % 3 is the same as 4 % 3 and hence have the same key value given the key mapping function. In this case you can provide a merge operator.

Here's one that sum the values; (i1, i2) -> i1 + i2; that can be replaced with the method reference Integer::sum.

Map<String, Integer> map = 
    intList.stream().collect(toMap(i -> String.valueOf(i % 3), 
                                   i -> i, 
                                   Integer::sum));

which now outputs:

0 => 9 (i.e 3 + 6)
1 => 5 (i.e 1 + 4)
2 => 7 (i.e 2 + 5)

Hope it helps! :)

Solution 3

Just in case this question isn't closed as a duplicate, the right answer is to use Google Collections:

Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
  public String apply(Role from) {
    return from.getName(); // or something else
  }});

Solution 4

Short and sweet.

Using Java 8 you can do following :

Map<Key, Value> result= results
                       .stream()
                       .collect(Collectors.toMap(Value::getName,Function.identity()));

Value can be any object you use.

Solution 5

Since Java 8, the answer by @ZouZou using the Collectors.toMap collector is certainly the idiomatic way to solve this problem.

And as this is such a common task, we can make it into a static utility.

That way the solution truly becomes a one-liner.

/**
 * Returns a map where each entry is an item of {@code list} mapped by the
 * key produced by applying {@code mapper} to the item.
 *
 * @param list the list to map
 * @param mapper the function to produce the key from a list item
 * @return the resulting map
 * @throws IllegalStateException on duplicate key
 */
public static <K, T> Map<K, T> toMapBy(List<T> list,
        Function<? super T, ? extends K> mapper) {
    return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
}

And here's how you would use it on a List<Student>:

Map<Long, Student> studentsById = toMapBy(students, Student::getId);
Share:
511,320

Related videos on Youtube

Rachel
Author by

Rachel

I am here for learning and I learn different aspects of Computer Science from the Valuable Answers which I get from Stackoverflow Users. Thank you SO Community. I owe my knowledge to you.

Updated on September 07, 2021

Comments

  • Rachel
    Rachel over 2 years

    Recently I have conversation with a colleague about what would be the optimal way to convert List to Map in Java and if there any specific benefits of doing so.

    I want to know optimal conversion approach and would really appreciate if any one can guide me.

    Is this good approach:

    List<Object[]> results;
    Map<Integer, String> resultsMap = new HashMap<Integer, String>();
    for (Object[] o : results) {
        resultsMap.put((Integer) o[0], (String) o[1]);
    }
    
    • Daniel Fath
      Daniel Fath over 13 years
      What's the best optimal way? Optimization is done with certain parameter (speed/memory) in mind.
    • Victor Sorokin
      Victor Sorokin over 13 years
      List differs from Map in the conceptual way -- Map have notion of 'key, value' pair, whereas List doesn't. Given this it's unclear how exactly you going to convert from List to Map and back.
    • Rachel
      Rachel over 13 years
      @Daniel: By Optimal, I meant what is the best way of doing so among all different ways between am not sure of all the ways and so it would be good to see some different ways of converting list to map.
    • ripper234
      ripper234 over 12 years
    • Lucky
      Lucky almost 5 years
    • akhil_mittal
      akhil_mittal over 4 years
      Java 8 HashMap and not any map implementation : stackoverflow.com/a/47736750/1216775
  • Jeremy
    Jeremy over 13 years
    You could also key on the position in the list.
  • Rachel
    Rachel over 13 years
    @Jim: Do i need to set the getKey() to any specific parameter ?
  • Rachel
    Rachel over 13 years
    Also what would be the value in the Map, can you elaborate with an example ?
  • Jeremy
    Jeremy over 13 years
    @Rachel -- The value is the item in the list, and the key is something that makes the item unique, which is determined by you. Jim's use of getKey() was arbitrary.
  • Rachel
    Rachel over 13 years
    But we can consider List Element position as key and put their value in map, is this a good solution ?
  • Rachel
    Rachel over 13 years
    @Jeremy: Ok. So basically I have element position in the list as the key and its value as value to populate the map, right ?
  • Rachel
    Rachel over 13 years
    What could be other ways of doing so ?
  • Rachel
    Rachel over 13 years
    Also, I have updated question with one approach that I have used, is this correct way of doing so ?
  • Daniel
    Daniel over 13 years
    AFAIK yes! There is no function in the JDK that does that automatically, so you have to roll your own.
  • Jim Garrison
    Jim Garrison about 11 years
    @Rachel No, you are using the same element as the key and value for ALL the objects. This will result in only one element being added to the list. If the list contains n elements, you will be adding the same duplicate map entry n times.
  • Víctor Romero
    Víctor Romero almost 11 years
    You know the size beforehand so you can do Map<Key,Item> map = new HashMap<Key,Item>(list.size());
  • glts
    glts over 9 years
    For a discussion of the type parameters of this method see my follow-up question.
  • Emmanuel Touzery
    Emmanuel Touzery over 9 years
    better use Function.identity() instead of item -> item
  • Tiny
    Tiny over 9 years
    "Guava contains a strictly compatible superset of the old, deprecated Google Collections Library. You should not use that library anymore." An update might be needed.
  • Alexis C.
    Alexis C. about 9 years
    @EmmanuelTouzery Well, Function.identity() returns t -> t;.
  • Emmanuel Touzery
    Emmanuel Touzery about 9 years
    Sure, both work. I guess it's a matter of taste. I find Function.identity() more immediately recognizable.
  • linuxdan
    linuxdan almost 9 years
    Use of an external library for such a simple operation is overkill. That or a sign of a very weak standard library. In this case @jim-garrison's answer is perfectly reasonable. It's sad that java doesn't have helpful methods like "map" and "reduce" but not entirely necessary.
  • IgorGanapolsky
    IgorGanapolsky over 8 years
    This uses Guava. Unfortunately Guava is super slow on Android, so this solution shouldn't be used in an Android project.
  • IgorGanapolsky
    IgorGanapolsky over 8 years
    How to use this? What should I pass as the converter parameter in the method?
  • phil294
    phil294 about 7 years
    OP doesnt handle any pojos, just strings and integer on whom you cannot cal ::getKey.
  • phil294
    phil294 about 7 years
    is it possible to do the last version (using array index as map key) with java 8 streams?
  • Alexis C.
    Alexis C. about 7 years
    @Blauhirn I know, my example is based on the custom class just below. You are free to use whatever function to generate your keys from the values .
  • Junchen Liu
    Junchen Liu almost 7 years
    if the item in the list has duplicated roleNames, the above code will throws exception,
  • glts
    glts almost 7 years
    @EMM Of course, as intended and documented in the Javadoc.
  • EMM
    EMM almost 7 years
    Yes, updated the answer for covering the case of duplicates. Please review. Thanks
  • Viktor Yarmak
    Viktor Yarmak over 6 years
    Using streams you will loose on performance, unless you are processing really big datasets - read comments here: stackoverflow.com/questions/22658322/… And here you can find more general an article on this: jaxenter.com/…
  • GP cyborg
    GP cyborg over 6 years
    This returns a ImmutableMap. Is there an alternative to this which returns a normal Mutable Map?
  • Harsh Sharma
    Harsh Sharma over 5 years
    FYI, stream API was added in API Level 24 in Android
  • George Fandango
    George Fandango over 5 years
    Nice one @AlexisC. this was very helpful to me :)
  • John Fantastico
    John Fantastico over 5 years
    Clean and adequate, and does not require a callback function for every item you process. By far the best response no matter what fancy stream or utility function is available.
  • Pavlo Morozov
    Pavlo Morozov over 4 years
    The funny fact that in 2019 huge amount of people still not realize that they are not know real Map implementation they get with lambda! Actually this is just one answer I found with Java 8 lambdas I would use on production.
  • Rosberg Linhares
    Rosberg Linhares over 4 years
    Is there a way to collect by specifying a Map type but without using a merge function?