J'essaye d'implémenter la fonction:
private static <T, K> Map<T, List<K>> invertedMap(Map<K, T> m) { return m.keySet().stream() .collect(Collectors.groupingBy(k -> m.get(k))); }
Par exemple si j'ai Map
,
Je souhaite créer une autre Map
.
J'ai écrit du code:
private static <T, K> Map<T, List<K> > invertedMap(Map<K, List<T> > m)
mais comme vous pouvez le voir, cela ne fonctionne que si la carte dans l'argument ne contient pas de liste comme valeurs.
4 Réponses :
Je n'utiliserais pas de flux pour cela (si vous voulez une solution basée sur le flux, consultez réponse de 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; }
Le code ci-dessus itère la carte d'entrée map
et pour chaque élément t
de chacun de sa List code > valeurs
l
, il utilise Map.computeIfAbsent
pour créer le résultat.
Map.computeIfAbsent
renvoie la valeur s'il y a une entrée pour la clé donnée, ou crée l'entrée et retourne la valeur spécifiée par son deuxième argument d -> new ArrayList ()
(ici d
représente un argument factice dont nous n'avons pas besoin pour créer une nouvelle liste vide). Ensuite, la clé k
est ajoutée à la liste renvoyée par Map.computeIfAbsent
.
Voici une façon stream de le faire (même si mon premier instinct lui-même serait de suivre la solution de Federico ):
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()))); }
J'espère que cela résoudra votre problème.
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; }
Cette solution est similaire à celle suggérée dans la réponse de Federico Peralta Schaffner , sauf qu'elle utilise pour
-loops au lieu de forEach
. Je poste principalement ceci pour avoir un MCVE et un court exemple de l'entrée / sortie, mais aussi comme contrepoids pour la solution basée sur le flux. Les gens peuvent désormais discuter de la lisibilité et de la maintenabilité.
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]
Le résultat est
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; } }
Pourriez-vous donner un exemple d'entrée et de résultat attendu?