Как перегруппировать древовидную карту с java потоками - PullRequest
4 голосов
/ 30 апреля 2020

У меня есть экземпляр TreeMap<Integer, Integer>, и я хочу переназначить сопоставления значений ключей таким образом, чтобы наименьшая клавиша была назначена наименьшему значению, а наивысшая клавиша - наивысшей клавише.

Вот как Я делаю это без потоков:

 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);

вывод:

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

Любые советы, как выполнить такую ​​задачу с использованием java -8 Stream API, приветствуются.

Thx

Ответы [ 2 ]

6 голосов
/ 30 апреля 2020

Я нашел решение, которое довольно легко читать и использовать:

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)); 

.. или меньше благодаря @ HadiJ :

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

... но он имеет существенный недостаток :

Я не могу гарантировать, что это будет работать параллельно, поскольку это зависит от результата keyIterator.next(), который также не проверяется. Подробнее читайте в разделе Поведение без гражданства . Я бы предпочел не использовать таким образом.


На вашем месте я бы использовал преимущество красоты итераторов:

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
}
4 голосов
/ 01 мая 2020

Ваш подход не плохой. Вы можете сократить его до

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

Я не думаю, что эта задача является хорошим кандидатом для Stream API.

...