11 votes

Java 8 Map of Collections supprimer un élément de la collection et supprimer l'entrée si elle est vide

J'ai une carte pour laquelle les valeurs sont une collection. Étant donné une clé, je veux supprimer un élément de la collection et le retourner, mais je veux également supprimer l'entrée si la collection est vide. Existe-t-il un moyen de faire cela de manière rapide en utilisant l'une des nombreuses nouvelles méthodes Map de Java 8 ?

Un exemple simple (j'utilise une pile mais il pourrait s'agir d'une liste, d'un ensemble, etc.) Pour les besoins de l'exemple, disons qu'il est déjà vérifié que la carte contient la clé.

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    Stack<String> stack = map.get(key);
    String result = stack.pop();
    if(stack.isEmpty()){
        map.remove(key);
    }
    return result;
}

J'ai essayé de faire quelque chose comme

map.compute(1, (k, v) -> {v.pop(); return v.size() == 0 ? null : v;});

Mais même s'il supprime effectivement l'entrée si elle est vide, je ne sais pas comment obtenir la valeur renvoyée par la fonction pop() .

5voto

Eugene Points 6271

Eh bien, c'est encore plus laid que ce que vous avez déjà en place, mais il y a un moyen, je suppose :

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    String[] removed = new String[1];
    map.compute(key, (k, v) -> {
        removed[0] = v.pop();
        return v.size() == 0 ? null : v;
    });
    return removed[0];
}

Le problème est que merge/compute et autres renvoient le valeur et dans votre cas, c'est un Stack/Set/List et non pas un élément individuel de cette collection.

4voto

nullpointer Points 1135

Ou vous pourriez éventuellement le réécrire en utilisant size comme :

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    return map.get(key).size() == 1 ? map.remove(key).pop() : map.get(key).pop();
}

2voto

Aomine Points 42709

I méthodes Map de Java 8 ?

Il n'y a pas de nouvelle méthode à partir de JDK8 qui améliorerait votre code, que ce soit en termes de lisibilité ou d'efficacité.

si vous faites cela comme un exercice pour vous-même, je peux comprendre dans une certaine mesure pourquoi vous voulez raccourcir le code ( si possible ) mais lorsqu'il s'agit de code de production, il faut éviter de jouer au golf et opter pour l'approche la plus lisible et la plus facile à maintenir ; peu importe si elle est plus longue.

Votre approche est bonne telle quelle.

2voto

MikeFHay Points 1201

Le Multimap de Guava gère la logique de suppression de la collection si elle est vide pour vous. Vous pouvez obtenir un comportement équivalent à votre méthode en deux lignes :

public static String removeOne(ListMultimap<Integer, String> map, int key) {
    List<String> stack = map.get(key);
    return stack.remove(stack.size() - 1);
}

Votre solution actuelle et la solution ci-dessus lèvent des exceptions si la carte ne contient pas d'entrées pour la clé donnée. En option, vous pouvez modifier le code pour gérer cela :

public static String removeOne(ListMultimap<Integer, String> map, int key) {
    List<String> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}

Et bien sûr, vous pouvez faire ce générique :

public static <K, V> V removeOne(ListMultimap<K, V> map, K key) {
    List<V> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}

1voto

ETO Points 5838

Je suis entièrement d'accord avec @NicholasK. Il n'y a aucune raison d'utiliser des flux ou des lambdas ici.

Votre approche est plutôt bonne. La seule chose que j'aimerais ajouter est de la rendre générique :

public static <K, E, C extends Collection<E>> E removeOne(Map<K, C> map, K key) {
    C col = map.get(key);
    Iterator<E> it = col.iterator();
    E e = it.next();
    it.remove();
    if (!it.hasNext()) {
        map.remove(key);
    }
    return e;
}

Cette méthode sera applicable à toutes les collections (valeurs de carte) renvoyant un itérateur valide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X