pero_hero
pero_hero

Reputation: 3194

How to regroup a treemap with java streams

I have a TreeMap<Integer, Integer> instance and I want to reassign the key value mappings in that way that the lowest key is assigned to the lowest value and the highest key to the highest key.

Here is how I do it without streams:

 TreeMap<Integer, Integer> map = new TreeMap<>();
 map.put(1, 6);
 map.put(2, 9);
 map.put(4, 2);
 map.put(3, 1);
 map.put(8, 10);
 map.put(5, 10);

 ArrayList<Integer> valueList = new ArrayList<Integer>(map.values());
 Collections.sort(valueList);

 int i = 0;
 for (Map.Entry entry : map.entrySet()) {
      entry.setValue(valueList.get(i++));
 }

 System.out.println(map);

output:

{1=1, 2=2, 3=6, 4=9, 5=10, 8=10}

Any hints how to perform such a task utilizing java-8 Stream API are welcome.

Thx

Upvotes: 4

Views: 595

Answers (2)

Holger
Holger

Reputation: 298389

Your approach is not bad. You can shorten it to

PriorityQueue<Integer> q = new PriorityQueue<>(map.values());
map.entrySet().forEach(e -> e.setValue(q.remove()));

I don't think that this task is a good candidate for the Stream API.

Upvotes: 4

Nikolas
Nikolas

Reputation: 44456

I have found out a solution that is fairly easy to read and use:

Iterator<Integer> keyIterator = map.keySet().iterator();
TreeMap<Integer, Integer> newMap = map.values().stream()
    .sorted()
    .map(value -> new SimpleEntry<>(keyIterator.next(), value))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (l, r) -> l, TreeMap::new)); 

.. or shorter thanks to @HadiJ:

map.values().stream()
            .sorted()
            .collect(Collectors.toMap(k -> keyIterator.next(),  Function.identity(), (l, r) -> l, TreeMap::new));

... but it has a significant drawback:

I cannot guarantee this will work in parallel since it depends on the result of keyIterator.next() which is also not checked. Read more at the section Stateless Behaviors. I'd rather not use in this way.


If I were you, I'd use the advantage of the beauty of iterators:

Iterator<Integer> values = valueList.iterator();
Iterator<Integer> keys = map.keySet().iterator();

TreeMap<Integer, Integer> newMap = new TreeMap<>();   // create a new Map
while (values.hasNext() && keys.hasNext()) {          // iterate simultaneously
    newMap.put(keys.next(), values.next());           // put the key-value
}

Upvotes: 5

Related Questions