Собрать для сопоставления значения порядка / позиции отсортированного потока - PullRequest
0 голосов
/ 25 мая 2018

Я сортирую заполненный набор MyObject (объект имеет метод getName ()) в потоке, используя предопределенный myComparator.

Затем, после сортировки, есть ли способ собрать в карту имяMyObject и порядок / позиция объекта из сортировки?

Вот как я думаю, это должно выглядеть так:

Set<MyObject> mySet;  // Already populated mySet 

Map<String, Integer> nameMap = mySet.stream()
        .sorted(myComparator)
        .collect(Collectors.toMap(MyObject::getName, //HowToGetThePositionOfTheObjectInTheStream));

Например, если набор содержит три объекта (object1 с именем name1, object2 с именем name2, object3 с именем name3) и во время потока они сортируются, как мне получить результирующую карту, которая выглядит следующим образом:

name1, 1
name2, 2
name3, 3

Спасибо.

Ответы [ 4 ]

0 голосов
/ 26 мая 2018

Самым простым решением будет цикл, поскольку формально правильное потоковое решение, которое также будет работать параллельно, требует нетривиальных (по сравнению с остальными) функций слияния:

Map<String,Integer> nameMap = mySet.stream()
    .sorted(myComparator)
    .collect(HashMap::new, (m, s) -> m.put(s.getName(), m.size()),
        (m1, m2) -> {
            int offset = m1.size();
            m2.forEach((k, v) -> m1.put(k, v + offset));
    });

Сравнение с циклом / коллекциейоперации:

List<MyObject> ordered = new ArrayList<>(mySet);
ordered.sort(myComparator);
Map<String, Integer> result = new HashMap<>();
for(MyObject o: ordered) result.put(o.getName(), result.size());

Оба решения предполагают уникальные элементы (поскольку может быть только одна позиция).Легко изменить цикл для выявления нарушений:

for(MyObject o: ordered)
    if(result.putIfAbsent(o.getName(), result.size()) != null)
        throw new IllegalStateException("duplicate " + o.getName());
0 голосов
/ 26 мая 2018

Попробуйте это.Вы можете использовать AtomicInteger для значения каждой записи карты.а также для гарантии порядка использования карты LinkedHashMap.

AtomicInteger index = new AtomicInteger(1);
Map<String, Integer> nameMap =  mySet.stream()
    .sorted(myComparator)
    .collect(Collectors
            .toMap(MyObject::getName, value -> index.getAndIncrement(),
                  (e1, e2) -> e1, LinkedHashMap::new));
0 голосов
/ 26 мая 2018

Не используйте поток:

List<MyObject> list = new ArrayList<>(mySet);
list.sort(myComparator);
Map<String, Integer> nameMap = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
    nameMap.put(list.get(i).getName(), i);
}

Мало того, что это будет выполняться быстрее, чем подход, основанный на потоках, все знают, что происходит.

Потоки имеют свое место, но до Java8 код тоже.

0 голосов
/ 25 мая 2018

Java Stream не предоставляет никакого индекса или расположения элементов, поэтому я не знаю способа заменить /*HowToGetThePositionOfTheObjectInTheStream*/ магией потоков для получения нужного числа.

Вместо этого, один простой способвместо этого собрать List, что дает каждому элементу индекс.Начинается с нуля, поэтому при преобразовании в карту добавьте 1.

List<String> inOrder = mySet.stream()
     .sorted(myComparator)
     .map(MyObject::getName)
     .collect(Collectors.toList());
Map<String, Integer> nameMap = new HashMap<>();
for (int i = 0; i < inOrder.size(); i++) {
    nameMap.put(inOrder.get(i), i + 1);
}
...