2 votes

Accéder et modifier l'ensemble d'entrée suivant tout en itérant une carte en Java

En travaillant sur un énoncé de problème, j'ai besoin d'accéder au prochain Entry d'un Map et en fonction d'une condition, je dois modifier la valeur de la prochaine entrée.

J'ai envisagé la solution proposée ici : Comment obtenir la clé/valeur précédente et la clé/valeur suivante dans Maps ? où je peux accéder au higherEntry en utilisant NavigableMap mais ça jette :

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractMap$SimpleImmutableEntry.setValue(AbstractMap.java:797)

ce qui est tout à fait compréhensible. Voici l'extrait de code

for (Map.Entry<Character, Integer> current : myMap.entrySet()) {

    Map.Entry<Character, Integer> next = myMap.higherEntry(current.getKey());

    if (current.getValue() == next.getValue()) {
        // Code block
    } else if (current.getValue() > next.getValue()) {
        // Code block
    } else {
        next.setValue(1); // Line that throws Exception
    }
}

Comment puis-je itérer dans un Map accéder à la prochaine entrée et la modifier, le cas échéant ?

0voto

SizableShrimp Points 498

Au lieu d'utiliser une boucle for améliorée, vous pouvez utiliser une boucle for normale et garder la trace de l'index. C'est délicat car il faut trouver un moyen d'accéder à l'entrée suivante et cela dépend si vous utilisez une implémentation ordonnée de Map (comme LinkedHashMap ). Si vous n'utilisez pas LinkedHashMap ou une carte ordonnée similaire, cela ne sera pas cohérent et les entrées risquent de ne pas être dans l'ordre. En supposant que vous son à l'aide d'une carte ordonnée, vous pouvez d'abord convertir l'ensemble des entrées en un tableau et partir de là. Cela ressemblerait à Map.Entry<Character, Integer>[] entries = myMap.entrySet().stream().toArray(Map.Entry[]::new); Ensuite, vous pouvez utiliser une boucle for avec ce tableau.

for (int i = 0; i < entries.length-1; i++) {
    Map.Entry<Character, Integer> current = entries[i];
    Map.Entry<Character, Integer> next = entries[i+1];
    //code that does stuff
}

0voto

ernest_k Points 14807

TreeMap.higherEntry renvoie un immuable et cela explique la UnsupportedOperationException que vous voyez :

//exportEntry is being called by TreeMap.higherEntry(K)
static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
    return (e == null) ? null :
        new AbstractMap.SimpleImmutableEntry<>(e);
}

Une solution possible consiste à rassembler les entrées mises à jour dans une carte, puis à modifier la carte originale après la boucle :

Map<Character, Integer> updates = new HashMap<>();

for (Map.Entry<Character, Integer> current : myMap.entrySet()) {

    Map.Entry<Character, Integer> next = myMap.higherEntry(current.getKey());

    if(null != next) {
        if (current.getValue() == next.getValue()) {
        } else if (current.getValue() > next.getValue()) {
        } else {
            updates.put(next.getKey(), 1); // entry to be updated
        }
    }
}

myMap.putAll(updates);

Notez que j'ai ajouté une vérification de nullité en tant que myMap.higherEntry peut revenir null .

0voto

N.Shrivastava Points 94
        Map.Entry<String, Integer> next = myMap.higherEntry(current.getKey());

        if(next != null)
        {
            if (current.getValue() == next.getValue())
            {
                //Code block
            }
            else if (current.getValue() > next.getValue()) {
                //Code block
            }

            else {
                myMap.put(current.getKey(), 1); 

            }
        }

0voto

Holger Points 13789

La méthode higherEntry renvoie une entrée immuable, mais votre code ne gère pas non plus le cas où il n'y a pas d'entrée supérieure. D'un autre côté, l'entrée suivante renvoyée par l'itérateur serait de toute façon la bonne entrée (s'il y en a une), donc cela peut être fait en utilisant une méthode de type Iterator manuellement, comme ceci :

Iterator<Map.Entry<Character, Integer>> it = myMap.entrySet().iterator();
if(it.hasNext()) {
    for(Map.Entry<Character, Integer> current=it.next(), next; it.hasNext(); current=next) {
        next = it.next();
        // don't compare Integer objects via ==, use equals
        if (current.getValue().equals(next.getValue())) {
            // Code block
        } else if (current.getValue() > next.getValue()) {
            // Code block
        } else {
            next.setValue(1);
        }
    }
}

Une alternative "moins propre" mais raisonnablement simple consisterait à

Map.Entry<Character, Integer> current = null;
for(Map.Entry<Character, Integer> next: myMap.entrySet()) {
    if(current != null) {
        if (current.getValue().equals(next.getValue())) {
            // Code block
        } else if (current.getValue() > next.getValue()) {
            // Code block
        } else {
            next.setValue(1);
        }
    }
    current = next;
}

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