Consider the following data structures:
ArrayList<HashMap<String, String>> entries = new ArrayList<>(); ArrayList<String> keyNamesToInclude = new ArrayList<>();
This code creates a copy of entries, but with hashmaps only including the keys in keyNamesToInclude:
ArrayList<HashMap<String, String>> copies = new ArrayList<>(); for (HashMap<String, String> entry: entries) { HashMap<String, String> copy = new HashMap<>(); for (String keyName: keyNamesToInclude) { copy.put(keyName, entry.get(keyName)); } copies.add(copy); }
How would one create this with Streams in a functional way?
Advertisement
Answer
It is better to convert keyNamesToInclude
into Set
to facilitate lookup of the keys.
Then use List::stream
to get Stream<HashMap>
and for each map get filtered stream of its entries re-collected into a new map and list accordingly.
Set<String> keys = new HashSet<>(keyNamesToInclude); // removes possible duplicates List<Map<String, String>> copies = entries.stream() // Stream<HashMap> .map(m -> m.entrySet() .stream() .filter(e -> keys.contains(e.getKey())) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue )) ) .collect(Collectors.toList());
If it is very important to have concrete implementations of List
and Map
in copies
, casting or special forms of collectors may be needed even though Collectors.toList()
returns ArrayList
and Collectors.toMap
returns HashMap
:
// casting ArrayList<HashMap<String, String>> copies2 = (ArrayList) entries.stream() // Stream<HashMap> .map(m -> (HashMap<String, String>) m.entrySet() .stream() .filter(e -> keys.contains(e.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) ) .collect(Collectors.toList()); // special collectors // toMap(keyMapper, valueMapper, mergeFunction, mapFactory) // toList -> toCollection(ArrayList::new) ArrayList<HashMap<String, String>> copies3 = entries.stream() // Stream<HashMap> .map(m -> m.entrySet() .stream() .filter(e -> keys.contains(e.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, HashMap::new)) ) .collect(Collectors.toCollection(ArrayList::new));