How to convert List to Map?
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 java-8, 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);
Related videos on Youtube
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, 2021Comments
-
Rachel over 2 years
Recently I have conversation with a colleague about what would be the optimal way to convert
List
toMap
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 over 13 yearsWhat's the best optimal way? Optimization is done with certain parameter (speed/memory) in mind.
-
Victor Sorokin over 13 yearsList 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 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 over 12 yearspossible duplicate of Java: how to convert a List<?> to a Map<String,?>
-
Lucky almost 5 yearsRead this article: How to Convert List to Map in Java
-
akhil_mittal over 4 yearsJava 8 HashMap and not any map implementation : stackoverflow.com/a/47736750/1216775
-
-
Jeremy over 13 yearsYou could also key on the position in the list.
-
Rachel over 13 years@Jim: Do i need to set the
getKey()
to any specific parameter ? -
Rachel over 13 yearsAlso what would be the value in the Map, can you elaborate with an example ?
-
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 over 13 yearsBut we can consider List Element position as key and put their value in map, is this a good solution ?
-
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 over 13 yearsWhat could be other ways of doing so ?
-
Rachel over 13 yearsAlso, I have updated question with one approach that I have used, is this correct way of doing so ?
-
Daniel over 13 yearsAFAIK yes! There is no function in the JDK that does that automatically, so you have to roll your own.
-
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 almost 11 yearsYou know the size beforehand so you can do Map<Key,Item> map = new HashMap<Key,Item>(list.size());
-
glts over 9 yearsFor a discussion of the type parameters of this method see my follow-up question.
-
Emmanuel Touzery over 9 yearsbetter use
Function.identity()
instead ofitem -> item
-
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. about 9 years@EmmanuelTouzery Well,
Function.identity()
returnst -> t;
. -
Emmanuel Touzery about 9 yearsSure, both work. I guess it's a matter of taste. I find Function.identity() more immediately recognizable.
-
linuxdan almost 9 yearsUse 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 over 8 yearsThis uses Guava. Unfortunately Guava is super slow on Android, so this solution shouldn't be used in an Android project.
-
IgorGanapolsky over 8 yearsHow to use this? What should I pass as the
converter
parameter in the method? -
phil294 about 7 yearsOP doesnt handle any pojos, just strings and integer on whom you cannot cal
::getKey
. -
phil294 about 7 yearsis it possible to do the last version (using array index as map key) with java 8 streams?
-
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 almost 7 yearsif the item in the list has duplicated roleNames, the above code will throws exception,
-
glts almost 7 years@EMM Of course, as intended and documented in the Javadoc.
-
EMM almost 7 yearsYes, updated the answer for covering the case of duplicates. Please review. Thanks
-
Viktor Yarmak over 6 yearsUsing 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 over 6 yearsThis returns a ImmutableMap. Is there an alternative to this which returns a normal Mutable Map?
-
Harsh Sharma over 5 yearsFYI, stream API was added in API Level 24 in Android
-
George Fandango over 5 yearsNice one @AlexisC. this was very helpful to me :)
-
John Fantastico over 5 yearsClean 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 over 4 yearsThe 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 over 4 yearsIs there a way to collect by specifying a Map type but without using a merge function?