At one point in my code, I created a Set<Map.Entry<K, V>>
from a map. Now I want to recreate the same map form, so I want to convert the HashSet<Map.Entry<K, V>>
back into a HashMap<K, V>
. Does Java have a native call for doing this, or do I have to loop over the set elements and build the map up manually?
There is no inbuilt API in java for direct conversion between HashSet
and HashMap
, you need to iterate through set and using Entry
fill in map.
one approach:
Map<Integer, String> map = new HashMap<Integer, String>();
//fill in map
Set<Entry<Integer, String>> set = map.entrySet();
Map<Integer, String> mapFromSet = new HashMap<Integer, String>();
for(Entry<Integer, String> entry : set)
{
mapFromSet.put(entry.getKey(), entry.getValue());
}
Though what is the purpose here, if you do any changes in Set
that will also reflect in Map
as set returned by Map.entrySet
is backup by Map
. See javadoc
below:
Set<Entry<Integer, String>> java.util.Map.entrySet()
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.
Simpler Java-8 solution involving Collectors.toMap
:
Map<Integer, String> mapFromSet = set.stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
An IllegalStateException
will be thrown if duplicate key is encountered.
There is no inbuilt API in java for direct conversion between HashSet
and HashMap
, you need to iterate through set and using Entry
fill in map.
one approach:
Map<Integer, String> map = new HashMap<Integer, String>();
//fill in map
Set<Entry<Integer, String>> set = map.entrySet();
Map<Integer, String> mapFromSet = new HashMap<Integer, String>();
for(Entry<Integer, String> entry : set)
{
mapFromSet.put(entry.getKey(), entry.getValue());
}
Though what is the purpose here, if you do any changes in Set
that will also reflect in Map
as set returned by Map.entrySet
is backup by Map
. See javadoc
below:
Set<Entry<Integer, String>> java.util.Map.entrySet()
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.
Fairly short Java 8 solution. Can cope with duplicate keys.
Map<Integer, String> map = new HashMap<>();
//fill in map
Set<Map.Entry<Integer, String>> set = map.entrySet();
Map<Integer, String> mapFromSet = set.stream().collect(Collectors.toMap(Entry::getKey,
Entry::getValue,
(a,b)->b));
Edit: thanks to shmosel who deserves more credit than I do for this
Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> b)
. –
Pacifist As of Guava 19 you can use ImmutableMap.copyOf(Iterable<Map.Entry<K,V>>)
Java 9+ without suppressed warning
As of the Java 9 version, the collection interfaces provide a bunch of handy static methods allowing you to do a lot of things inline. There is a built-in solution using a static method Map.ofEntries(Map.Entry... entries)
which creates an immutable map.
Map<Integer,String> map = Map.ofEntries(
new SimpleEntry<>(1, "one"),
new SimpleEntry<>(2, "two"),
new SimpleEntry<>(3, "three"));
Note that also the Map.entry(K, V)
method is available which makes everything less verbose.
Map<Integer,String> map2 = Map.ofEntries(
Map.entry(1, "one"),
Map.entry(2, "two"),
Map.entry(3, "three"));
Assuming you have Set<Map.Entry<K, V>>
, you need an array to use the method using Set#toArray(T[])
. Explicit casting is required due to forbidden generic array creation, which is the only drawback of this solution.
Set<Map.Entry<Integer,String>> set = ...
Entry<Integer, String>[] entries = set.<Entry<Integer,String>>toArray(Entry[]::new);
Map<Integer,String> map = Map.ofEntries(entries);
Java 8
Java 8 brings Stream API which is pretty straightforward using Collectors.toMap(keyFn, valueFn)
.
Set<Map.Entry<Integer,String>> set = ...
Map<Integer,String> map = set.stream()
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue));
To avoid erroneous behavior in the presence of two Map.Entry
with the same keys that are forbidden in dictionaries, use Collectors.toMap(keyFn, valueFn, mergeFn)
. Return either first
or second
depending on if you want to keep the first value found for a certain key or the latest one.
Map<Integer,String> map = set.stream()
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue,
(first, second) -> first)); // if you need the 1st occurrence
// (first, second) -> second)); // if you need the last occurrence
Java 7 and older
All, you can do is a procedural for-each iteration as the existing answer describes.
As of 2018, there are some toMap
utility in Apache libraries, but unfortunately most of them take an array instead of Set
, so you need to do Set#toArray()
first.
I left Guava out for @Neil's answer which is arguably the best.
Apache Commons Collections' MapUtils.putAll
Map<K, V> map = MapUtils.putAll(new HashMap<K, V>(), entrySet.toArray());
Apache Commons Collections' MapUtils.populateMap
HashMap<K, V> map = new HashMap<>();
MapUtils.populateMap(map, entrySet, Map.Entry::getKey, Map.Entry::getValue);
Apache Commons Lang's ArrayUtils.toMap
Map<Object, Object> map = ArrayUtils.toMap(entrySet.toArray());
// to recover the type...
@SuppressWarnings("unchecked")
Map<K, V> typedMap = (Map<K, V>)(Map<?, ?>)map;
Java 9's Map.ofEntries
// convert to array and recover the type...
@SuppressWarnings("unchecked")
Map<K, V> map = Map.ofEntries(entrySet.toArray(new Map.Entry[entrySet.size()]));
// Somehow this makes javac happy
IntFunction<Map.Entry<K, V>[]> c = Map.Entry[]::new;
Map<K, V> map2 = Map.ofEntries(entrySet.toArray(c.apply(entrySet.size())));
// Using an overload available since Java 11
Map<K, V> map3 = Map.ofEntries(entrySet.toArray(c));
// You need to copy again if you want a mutable one
Map<K, V> hashmap = new HashMap<>(map);
In Java 8 with correct combiner
Map<Integer, String> map = new HashMap<>();
//fill in map
Set<Map.Entry<Integer, String>> set = map.entrySet();
Map<Integer, String> mapFromSet =set.stream().collect(HashMap::new,(t, u) -> t.put(u.getKey(), u.getValue()),
(Map mapToReturn, Map otherMap) ->
{
otherMap.entrySet().forEach((Map.Entry entry) -> {
mapToReturn.put(entry.getKey(),entry.getValue());
});
return mapToReturn;}););
I wanted to try this for a practice problem. My issue was that I needed to convert two "maps" into "sets" so I can use the math operations that come with sets, like Union, Intersection, and Difference. While learning about "Map.Entry" I found I could convert the "Maps" into "Sets" perform the math operation as required. However, I still needed to convert my return value back into a "Map" per problem requirements. I found that I could do this if you typecast the objects back into the original variables. My end result is a "Map" that includes only the Intersections of both Maps.
public static Map<String, Integer> intersect(Map<String, Integer> map_one, Map<String, Integer> map_two)
{
Set<Map.Entry<String, Integer>> set_one = map_one.entrySet(); //Map one now a set
Set<Map.Entry<String, Integer>> set_two = map_two.entrySet(); //Map two now a set
set_one.retainAll(set_two); //a math intersection operation set_one and set_two whose contents are the intersection of the two sets
Map<String, Integer> map_retur = new HashMap<>(); //instantiation of a new Map object
Iterator i = set_one.iterator(); //instantiation of an iterator
while(i.hasNext())
{
Map.Entry me = (Map.Entry)i.next(); // instantiation of Map.Entry as me and convert i into that Map.Entry
map_retur.put((String)me.getKey(), (Integer)me.getValue()); // store each key/value pair into the Map as required
}
return map_retur; // returned value is a map with only the intersections
}
Thanks Ref: https://www.tutorialspoint.com/java/java_mapentry_interface.html For how to do the iterations in the for each loop. However, it does not include the typecasting I have shown here.
© 2022 - 2024 — McMap. All rights reserved.
Set
fromMap
, using key or value or custom logic? besides there is nonative
method forHashSet
toHashMap
. You need to iterate and use some logic as while putting intoHashMap
how you choose key and value. – SuitMap.Entry
is meant to be used this way. Does the implementation used byHashMap
overridehashCode
andequals
for example? – Congruity