I have a Map<String, String>
and a List<String>
. I'd like to partition the Map
based on the condition
foreach(map.key -> list.contains(map.key))
and produce two Map
(s). What's the most elegant way to do so? I'm on Java 11, so you can throw everything you want in the answers.
What I came up to for now is:
map.entrySet()
.stream()
.collect(partitioningBy(e -> list.contains(o.getKey())));
but that gives a Map<Boolean, List<Entry<String, String>>>
.
First, we create a result map with two entries, one for each partition. The values are LinkedHashMap s so that insertion order is preserved. Then, we create a HashSet from the list, so that invoking set. contains(k) is a O(1) operation (otherwise, if we did list.
Collectors partitioningBy() method in Java 8 The partioningBy() method returns a Collector that partitions the input elements according to a Predicate, and organizes them into a Map<Boolean, List<T>>.
java. In number theory, * a partition of N is a way to write it as a sum of positive integers. * Two sums that differ only in the order of their terms are considered * the same partition.
You can reduce each group using toMap
(as a downstream collector):
Map<String, String> myMap = new HashMap<>(); myMap.put("d", "D"); myMap.put("c", "C"); myMap.put("b", "B"); myMap.put("A", "A"); List<String> myList = Arrays.asList("a", "b", "c"); Map<Boolean, Map<String, String>> result = myMap.entrySet() .stream() .collect(Collectors.partitioningBy( entry -> myList.contains(entry.getKey()), Collectors.toMap(Entry::getKey, Entry::getValue) ) );
And for this example, that produces {false={A=A, d=D}, true={b=B, c=C}}
Though partitioningBy
is the way to go when you need both the alternatives as an output based on the condition. Yet, another way out (useful for creating map based on a single condition) is to use Collectors.filtering
as :
Map<String, String> myMap = Map.of("d", "D","c", "C","b", "B","A", "A");
List<String> myList = List.of("a", "b", "c");
Predicate<String> condition = myList::contains;
Map<String, String> keysPresentInList = myMap.keySet()
.stream()
.collect(Collectors.filtering(condition,
Collectors.toMap(Function.identity(), myMap::get)));
Map<String, String> keysNotPresentInList = myMap.keySet()
.stream()
.collect(Collectors.filtering(Predicate.not(condition),
Collectors.toMap(Function.identity(), myMap::get)));
or alternatively, if you could update the existing map in-place, then you could retain entries based on their key's presence in the list using just a one-liner:
myMap.keySet().retainAll(myList);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With