Разделите ключи карты и создайте новую карту с новыми ключами и соответствующими значениями - PullRequest
0 голосов
/ 18 февраля 2019

У меня есть List из Objects, что каждый из них содержит значение X, Y (Doubles) и имя String.Поскольку у меня есть несколько записей с одинаковыми именами, которые соответствуют координатам, я хочу связать каждое имя со всеми координатами, что мне удалось сделать, создав Map типа <String, List<Object>>

Пример вывода:

One             [[0.1,0.1,0.1],[0.2,0.3,0.4]]
One,Two         [[0.1,0.1]    ,[0.4,0.5]]         
One,Two,Three   [[0.1,0.1]    ,[0.6,0.7]]

Теперь я хочу разделить имена с запятой , и получить следующий результат:

One   [[0.1,0.1,0.1,0.1,0.1,0.1],[0.2,0.3,0.4,0.5,0.6,0.7]]
Two   [[0.01,0.01,0.01,0.01]    ,[0.4,0.5,0.6,0.7]]                    
Three [[0.01,0.01]              ,[0.6,0.7]]

Мой код, который РАБОТАЕТ:

Map<String, List<Coordinates>> newList = coordinateList.stream()
                .collect(Collectors.groupingBy(Coordinates::getName));

, который создает первый Map.

Чтобы выполнить вторую часть, я попробовал следующее вместе с различными комбинациями, но безуспешно:

newList.entrySet().stream()
        .flatMap(entry -> Arrays.stream(entry.getKey().split(","))
                .map(s -> new AbstractMap.SimpleEntry<>(s, entry.getValue())))
        .collect(Collectors.groupingBy(Map.Entry::getKey, 
                Collectors.flatMapping(entry -> entry.getValue().stream(), Collectors.toList())));

Я получаю сообщение об ошибке:

The method flatMapping((<no type> entry) -> {}, Collectors.toList()) is undefined for the type Collectors

Обратите внимание, что изменение flatMapping на mapping работает, но не решает проблему.

Еще один вариант кода, которыйЯ попробовал это:

Map<String, List<Object>> collect1 = map.entrySet().stream()
        .flatMap(entry -> Arrays.stream(entry.getKey().split(","))
                .map(s -> new AbstractMap.SimpleEntry<>(s, entry.getValue())))
        .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())))
        .entrySet().stream()
        .flatMap(entry -> entry.getValue().stream()
                .flatMap(Collection::stream)
                .map(o -> new AbstractMap.SimpleEntry<>(entry.getKey(), o)))
        .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));

Все еще не повезло, и я регулярно получаю ошибку Cannot infer type argument(s) for <R> flatMap(Function<? super T,? extends Stream<? extends R>>)

Есть идеи?

1 Ответ

0 голосов
/ 19 февраля 2019

Кажется, вы не используете java9.Если вы используете Java9, первый подход с Collectors.flatMapping будет работать.Но я все еще не вижу смысла в создании нового Map.Entry здесь.Взгляните на это решение.

private static final Pattern COMMA_DELIMITER = Pattern.compile(",\\s*");

Map<String, Set<Coordinate>> nameToCoordinates = coordinates.stream()
    .flatMap(
        c -> COMMA_DELIMITER.splitAsStream(c.getName())
            .map(n -> new Coordinate(n, c.getX(), c.getY())))
    .collect(Collectors.groupingBy(Coordinate::getName, Collectors.toSet()));

Для каждой координаты возьмите ее имя и разделите его, используя разделитель, а затем для каждого такого токена имени создайте новую координату с этим новым именем и координатами x, y.,Затем просто соберите его, используя сборщик groupingBy.Поскольку вам нужно хранить только отдельные значения Coordinate, вы должны переопределить методы equals и hashCode в классе Coordinate.Вот как это выглядит.

@Override
public int hashCode() {
    int result = name.hashCode();
    result = 31 * result + Double.hashCode(x);
    result = 31 * result + Double.hashCode(y);
    return result;
}

@Override
public boolean equals(Object obj) {
    return obj instanceof Coordinate && ((Coordinate) obj).getX() == x 
        && ((Coordinate) obj).getY() == y
        && ((Coordinate) obj).getName().equals(name);
}

По какой-то причине, если вам действительно нужно использовать промежуточную карту, созданную на первом шаге, ваше решение будет выглядеть следующим образом.

newList.values().stream().flatMap(Collection::stream)
    .flatMap(
        c -> COMMA_DELIMITER.splitAsStream(c.getName())
            .map(n -> new Coordinate(n, c.getX(), c.getY())))
    .collect(Collectors.groupingBy(Coordinate::getName, Collectors.toSet()));

Вотвыход.

{Один = [[имя = Один, х = 0,1, у = 0,2], [имя = Один, х = 0,1, у = 0,4], [имя = Один, х= 0,1, у = 0,3], [имя = один, х = 0,1, у = 0,5], [имя = один, х = 0,1, у = 0,6], [имя = один, х = 0,1, у = 0,7]], Два = [[имя = два, х = 0,1, у = 0,4], [имя = два, х = 0,1, у = 0,5], [имя = два, х = 0,1, у = 0,6], [имя = два, х = 0,1, у = 0,7]], три = [[имя = три, х = 0,1, у = 0,6], [имя = три, х = 0,1, у = 0,7]]}

...