2016-12-06 1 views
2

J'ai besoin d'inverser une carte originale. lequel type est <Integer, String>, comme {1 = A, 2 = A, 3 = B....}. Je veux créer une nouvelle carte qui est String à ArrayList parce que si 1 = A, et 2 = A, que je veux avoir quelque chose comme: A = [1, 2].Java inverser une carte

Alors, comment puis-je faire cela?

+1

de parcourir la carte existante? – BevynQ

+0

http://stackoverflow.com/questions/3678601/how-to-do-map-inversion-with-guava-with-non-unique-values ​​ –

+0

Ouais je pense que j'ai besoin de répéter une fois et obtenir des clés ou des valeurs à moins. – Anderson

Répondre

3

Vous pouvez essayer ceci:

HashMap<Integer, String> original = new HashMap<>(); 
HashMap<String, ArrayList<Integer>> inverted = new HashMap<>(); 

original.put(1, "A"); 
original.put(2, "B"); 
original.put(3, "C"); 
original.put(4, "A"); 

for (Integer key: original.keySet()) { 
    String newKey = original.get(key); 

    inverted.computeIfAbsent(newKey, k -> new ArrayList<>()); 
    inverted.get(newKey).add(key); 

} 
System.out.println(original); 
System.out.println(inverted); 

Alors, disons que HashMap<Integer, String> original est {1=A, 2=B, 3=C, 4=A}, alors vous obtiendrez {A=[1, 4], B=[2], C=[3]}.

EDIT: Si vous voulez une version plus générique, comme @ Mr.Polywhirl a suggéré, vous pouvez utiliser:

public static final <T, U> Map<U, List<T>> invertMap(Map<T, U> map) { 
    HashMap<U, List<T>> invertedMap = new HashMap<>(); 

    for (T key : map.keySet()) { 
     U newKey = map.get(key); 

     invertedMap.computeIfAbsent(newKey, k -> new ArrayList<>()); 
     invertedMap.get(newKey).add(key); 

    } 

    return invertedMap; 
} 
+0

Le problème avec ceci (par opposition à la version originale que vous avez publiée) est que ceci exige 2 recherches de hash par index. Si votre hash est trivial comme dans l'exemple, pas de biggie. Si vous avez plusieurs centaines d'objets dedans, vous devriez le faire dans l'autre sens pour l'accélération - il ne devrait pas y en avoir plus d'un ici (computeIfAbsent doit faire un get pour voir si l'item existe). –

+0

@GabeSechan, n'hésitez pas à modifier ma réponse pour rendre ce code plus efficace. Je n'ai pas une grande connaissance de Java. – lmiguelvargasf

+0

Voici une version générique du code ci-dessus. N'hésitez pas à l'ajouter à votre réponse. http://pastebin.com/yTExx5Fi –

4

Vous pouvez facilement le faire en utilisant Java 8 API stream, ci-dessous est un exemple :

public static void main(String[] args) throws FileNotFoundException { 

    Map<Integer, String> map = new HashMap<>(); 
    map.put(1, "A"); 
    map.put(2, "A"); 
    map.put(3, "B"); 

    Map<String, List<Integer>> invertedMap = map.entrySet() 
    .stream() 
    .collect(Collectors.groupingBy(Entry::getValue, 
      Collectors.mapping(Entry::getKey, Collectors.toList()))); 

    System.out.println(invertedMap); 

} 
+1

Je ne comprends vraiment pas pourquoi les gens préfèrent utiliser une approche de flux pour un problème comme celui-ci. Il semble être un code de non-auto non-intuitif. Comment est-ce mieux que l'exemple de bouclage traditionnel? – bhspencer

+1

Je ne vais pas rétrograder parce que ce n'est pas faux, mais je rebondirais sur une codereview. Bien trop difficile de comprendre ce que fait le code et si vous changez les exigences, il n'y a aucun moyen de le modifier, vous devrez le réécrire complètement. –

+2

Consensnsus général ici, si Java fournit déjà des bibliothèques/API pour quelque chose, je préfère l'utiliser que d'écrire mon propre code standard (qui ne sera pas aussi efficace que les API natives Java de toute façon). –