Как создать картувне карты? - PullRequest
0 голосов
/ 07 февраля 2019

Я пытаюсь реализовать функцию:

private static <T, K> Map<T, List<K> > invertedMap(Map<K, List<T> > m)

Например, если у меня есть Map<String, List<Integer> >,

Я хочу создать еще один Map<Integer, List<String> >.

Я написал некоторый код:

private static <T, K> Map<T, List<K>> invertedMap(Map<K, T> m) {
    return m.keySet().stream()
            .collect(Collectors.groupingBy(k -> m.get(k)));
}

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

Ответы [ 4 ]

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

Это решение аналогично предложенному в ответе Федерико Перальта Шаффнера , за исключением того, что вместо forEach он использует for -loops.Я в основном публикую это, чтобы иметь MCVE и короткий пример ввода / вывода, но также в качестве противовеса для потокового решения.Теперь люди могут спорить о удобочитаемости и удобстве обслуживания.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class InvertMapWithLists
{
    public static void main(String[] args)
    {
        Map<String, List<Integer>> map = 
            new LinkedHashMap<String, List<Integer>>();
        map.put("A", Arrays.asList(0,1,2));
        map.put("B", Arrays.asList(2,3,4));
        map.put("C", Arrays.asList(4,5,6));

        System.out.println("Original:");
        map.entrySet().forEach(System.out::println);

        Map<Integer, List<String>> inverted = invert(map);

        System.out.println("Inverted");
        inverted.entrySet().forEach(System.out::println);
    }


    private static <T, K> Map<T, List<K>> invert(
        Map<K, ? extends Collection<? extends T>> map)
    {
        Map<T, List<K>> result = new LinkedHashMap<T, List<K>>();

        for (Entry<K, ? extends Collection<? extends T>> entry : map.entrySet())
        {
            for (T element : entry.getValue())
            {
                List<K> list = result.computeIfAbsent(
                    element, v -> new ArrayList<K>());
                list.add(entry.getKey());
            }
        }
        return result;
    }
}

Вывод:

Original:
A=[0, 1, 2]
B=[2, 3, 4]
C=[4, 5, 6]
Inverted
0=[A]
1=[A]
2=[A, B]
3=[B]
4=[B, C]
5=[C]
6=[C]
0 голосов
/ 07 февраля 2019

Вот способ потока (хотя мой первый инстинкт сам должен был бы следовать решению Федерико ):

private static <T, K> Map<T, List<K>> invertedMapOfList(Map<K, List<T>> m) {
    return m.entrySet()
        .stream()
        .flatMap(e -> e.getValue()
            .stream()
            .map(v -> new AbstractMap.SimpleEntry<>(e.getKey(), v)))
        .collect(Collectors.groupingBy(Map.Entry::getValue,
            Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
}
0 голосов
/ 07 февраля 2019

Надеюсь, что это решит вашу проблему.

private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> m) {
    Map<T, List<K>> result = new HashMap<T, List<K>>();

    for (K key : m.keySet()) {
        for (T value : m.get(key)) {
            List<K> kList = null;
            if ((kList = result.get(value)) == null) {
                kList = new ArrayList<K>();
            }
            kList.add(key);
            result.put(value, kList);
        }
    }
    return result;
}
0 голосов
/ 07 февраля 2019

Я бы не использовал потоки для этого (если вы хотите решение на основе потоков, проверьте ответ nullpointer ):

private static <T, K> Map<T, List<K>> invertedMap(Map<K, List<T>> map) {
    Map<T, List<K>> result = new LinkedHashMap<>(); // Preserves insertion order 
    map.forEach((k, l) -> 
           l.forEach(t -> result.computeIfAbsent(t, d -> new ArrayList<>()).add(k)));
    return result;
}

Приведенный выше код повторяет карту ввода map и для каждого элемента t каждого из его List значений l он использует Map.computeIfAbsent для создания результата.

Map.computeIfAbsent возвращает значение, если есть запись для данного ключа, или создает запись и возвращает значение, указанное его вторым аргументом d -> new ArrayList<>() (здесь d обозначает фиктивный аргумент, который мы передаемне нужно для того, чтобы создать новый, пустой список).Затем ключ k добавляется в список, возвращаемый Map.computeIfAbsent.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...