what is the best way to get a sub HashMap based on a list of Keys?
Solution 1
With Java8 streams, there is a functional (elegant) solution. If keys
is the list of keys to keep and map
is the source Map
.
keys.stream()
.filter(map::containsKey)
.collect(Collectors.toMap(Function.identity(), map::get));
Complete example:
List<Integer> keys = new ArrayList<>();
keys.add(2);
keys.add(3);
keys.add(42); // this key is not in the map
Map<Integer, String> map = new HashMap<>();
map.put(1, "foo");
map.put(2, "bar");
map.put(3, "fizz");
map.put(4, "buz");
Map<Integer, String> res = keys.stream()
.filter(map::containsKey)
.collect(Collectors.toMap(Function.identity(), map::get));
System.out.println(res.toString());
Prints: {2=bar, 3=fizz}
EDIT add a filter
for keys that are absent from the map
Solution 2
Yes there is a solution:
Map<K,V> myMap = ...;
List<K> keysToRetain = ...;
myMap.keySet().retainAll(keysToRetain);
The retainAll
operation on the Set
updates the underlying map. See java doc.
Edit
Be aware this solution modify the Map
.
Solution 3
With a help of Guava.
Suppose you have a map Map<String, String>
and want to submap with a values from List<String>
list.
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "4");
final List<String> list = Arrays.asList("2", "4");
Map<String, String> subMap = Maps.filterValues(
map, Predicates.in(list));
Update / Note: As @assylias mentioned in the comment, you will have O(n) when using contains()
. So if you have large list, this could have huge impact in performance.
On the other side HashSet.contains()
is constant time O(1), so if there is a possibility to have Set instead of List, this could be a nice approach (note that converting List to Set will cost O(n) anyway, so better not to convert :))
Solution 4
If you have Map m1 and List keys, then try following
Map m2 = new HashMap(m1);
m2.keySet().retainAll(keys);
Solution 5
Depending on your usage, this may be a more efficient implementation
public class MapView implements Map{
List ak;
Map map;
public MapView(Map map, List allowableKeys) {
ak = allowableKeys;
map = map;
}
public Object get(Object key) {
if (!ak.contains(key)) return null;
return map.get(key);
}
}
aregnier
Updated on March 30, 2021Comments
-
aregnier over 3 years
I have a HashMap and I would like to get a new HashMap that contains only the elements from the first HashMap where K belongs to a specific List.
I could look through all the keys and fillup a new HashMap but I was wondering if there is a more efficient way to do it?
thanks