简体   繁体   中英

How to overwrite values of HashMap from ArrayList using Java 8 Streams

I have this code in which I am overwriting values of Map from an ArrayList.
I want to write this code using Streams and Lambda expression

List<Integer> list = new ArrayList<Integer>(arrayList);
        
        Collections.sort(list, Collections.reverseOrder());

        int i = 0;
        Iterator<Entry<Integer, Integer>> itr = sortedMap.entrySet().iterator();
        while(itr.hasNext()) {
            Entry<Integer, Integer> pair = itr.next();
            pair.setValue(list.get(i));
            ++i;
        }

Thank You!

You could convert the map keys to a list, and then loop through both map keys and sorted list simultaneously using IntStream:

List<Integer> list = new ArrayList<>(arrayList);
Collections.sort(list, Collections.reverseOrder());

List<Integer> mapKeys = new ArrayList<>(sortedMap.keySet());

Map<Integer,Integer> overwrittenMap = 
            IntStream.range(0,mapKeys.size())
                     .boxed()
                     .collect(TreeMap::new, 
                             (map,i) -> map.put(mapKeys.get(i),list.get(i)),
                             Map::putAll);

This can be implemented in different ways:

  1. Convert keySet of the sorted map into list and use indexes to build a map using Collectors.toMap :
List<Integer> keys = new ArrayList<>(map.keySet());
Map<Integer, Integer> res = IntStream
        .range(0, list.size())
        .boxed()
        .collect(Collectors.toMap(i -> keys.get(i), i -> list.get(i), (a, b)-> a, TreeMap::new));
System.out.println(res);
  1. Use AtomicInteger and its getAndIncrement when streaming by keys of the sorted map to refer the element in the list with the updates:
AtomicInteger i = new AtomicInteger(0);
Map<Integer, Integer> res2 = map.keySet()
                                .stream()
                                .collect(Collectors.toMap(
                                    k -> k, 
                                    k -> list.get(i.getAndIncrement()), 
                                    (a, b) -> a, 
                                    TreeMap::new // or LinkedHashMap::new as keys are sorted
                                ));
System.out.println(res2);
  1. Similarly to previous implementation, current map may be modified using forEach of the map's entrySet() :
AtomicInteger j = new AtomicInteger(0);
map.entrySet().forEach(e -> e.setValue(list.get(j.getAndIncrement())));

Extra safety measures may need to be added, for instance, handling of the case when the map and the list are of different size.

These examples prove the feasibility of such task, though the task itself does not seem to be an appropriate application of Stream API.

Doing literally the same as your original code, ie set the values of the existing sortedMap in descending order, can be achieved as

Iterator<Integer> values = arrayList.stream()
        .sorted(Collections.reverseOrder())
        .iterator();

sortedMap.replaceAll((key,value) -> values.next());

This assumes that the list and the map have the same size, as you acknowledged in a comment, ie it does not check for the end of the Iterator .

It's important that sortedMap truly has to be a SortedMap or a map implementation maintaining an order in general, which excludes the HashMap mentioned in the title of your question. Otherwise, it's pointless to sort the values of the arrayList

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM