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?