Question

Je comprends que l'ensemble est retourné à partir de la méthode KeySet () d'une carte ne garantit aucun ordre particulier.

Ma question est, garantit-elle le même commander sur plusieurs itérations. Par exemple

Map<K,V> map = getMap();

for( K k : map.keySet() )
{
}

...

for( K k : map.keySet() )
{
}

Dans le code ci-dessus, en supposant que la carte est ne pas Modifié, l'itération sur lessets de touches sera-t-elle dans le même ordre. En utilisant JDK15 de Sun Est-ce que Itérer dans le même ordre, mais avant de dépendre de ce comportement, j'aimerais savoir si tous les JDK feront de même.

ÉDITER

Je vois sur les réponses que je ne peux pas en dépendre. Dommage. J'espérais m'en tirer sans avoir à construire une nouvelle collection pour garantir ma commande. Mon code avait besoin de parcourir, de faire de la logique, puis de parcourir à nouveau avec le même ordre. Je vais simplement créer une nouvelle ArrayList à partir de la clé qui garantira la commande.

Était-ce utile?

La solution

S'il n'est pas dit qu'il est garanti dans la documentation de l'API, vous ne devriez pas en dépendre. Le comportement pourrait même passer d'une version du JDK à la suivante, même du JDK du même fournisseur.

Vous pouvez facilement obtenir l'ensemble et ensuite le trier vous-même, non?

Autres conseils

Vous pouvez utiliser un LinkedHashmap Si vous voulez un hashmap dont l'ordre d'itération ne change pas.

De plus, vous devez toujours l'utiliser si vous itérez dans la collection. L'itération de l'entrée ou de la clé de Hashmap est beaucoup plus lente que sur LinkedHashmap.

La carte n'est qu'une interface (plutôt qu'une classe), ce qui signifie que la classe sous-jacente qui l'implémente (et il y en a beaucoup) pourrait se comporter différemment, et que le contrat pour KeySet () dans l'API n'indique pas qu'une itération cohérente est requise.

Si vous envisagez une classe spécifique qui implémente la carte (hashmap, linkedhashmap, treemap, etc.), vous pouvez voir comment il implémente la fonction keyset () pour déterminer quel serait le comportement en vérifiant la source, vous devrez Jetez vraiment un coup d'œil à l'algorithme pour voir si la propriété que vous recherchez est conservée (c'est-à-dire l'ordre d'itération cohérent lorsque la carte n'a pas eu d'insertions / déménagements entre les itérations). La source de HashMap, par exemple, est ici (Open JDK 6): http://www.docjar.com/html/api/java/util/hashmap.java.html

Cela pourrait varier considérablement d'un JDK à l'autre, donc je n'en compterais certainement pas.

Cela étant dit, si l'ordre d'itération cohérent est quelque chose dont vous avez vraiment besoin, vous voudrez peut-être essayer un lien hashmap.

L'API pour la carte ne garantit pas n'importe quel Commande quoi que ce soit, même entre plusieurs invocations de la méthode sur le même objet.

Dans la pratique, je serais très surpris si l'ordre d'itération modifiait pour plusieurs invocations ultérieures (en supposant que la carte elle-même ne changeait pas entre les deux) - mais vous ne devriez pas (et selon l'API ne peut pas s'appuyer sur cela.

EDIT - Si vous souhaitez compter sur l'ordre d'itération cohérent, alors vous voulez un Trié qui fournit exactement ces garanties.

Juste pour le plaisir, j'ai décidé d'écrire un code que vous pouvez utiliser pour garantir une commande aléatoire à chaque fois. Ceci est utile pour que vous puissiez prendre des cas où vous dépendez de la commande, mais vous ne devriez pas l'être. Si vous souhaitez dépendre de la commande, comme d'autres l'ont dit, vous devez utiliser un tri. Si vous utilisez simplement une carte et que vous comptez sur l'ordre, l'utilisation du Randomditerator suivant l'attrapera. Je ne l'utiliserais que dans le code de test car il utilise plus de mémoire que ne le ferait pas.

Vous pouvez également envelopper la carte (ou l'ensemble) pour les faire renvoyer le Randomeiterator qui vous permettrait ensuite d'utiliser la boucle For-out.

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Main
{
    private Main()
    {
    }

    public static void main(final String[] args)
    {
        final Map<String, String> items;

        items = new HashMap<String, String>();
        items.put("A", "1");
        items.put("B", "2");
        items.put("C", "3");
        items.put("D", "4");
        items.put("E", "5");
        items.put("F", "6");
        items.put("G", "7");

        display(items.keySet().iterator());
        System.out.println("---");

        display(items.keySet().iterator());
        System.out.println("---");

        display(new RandomIterator<String>(items.keySet().iterator()));
        System.out.println("---");

        display(new RandomIterator<String>(items.keySet().iterator()));
        System.out.println("---");
    }

    private static <T> void display(final Iterator<T> iterator)
    {
        while(iterator.hasNext())
        {
            final T item;

            item = iterator.next();
            System.out.println(item);
        }
    }
}

class RandomIterator<T>
    implements Iterator<T>
{
    private final Iterator<T> iterator;

    public RandomIterator(final Iterator<T> i)
    {
        final List<T> items;

        items = new ArrayList<T>();

        while(i.hasNext())
        {
            final T item;

            item = i.next();
            items.add(item);
        }

        Collections.shuffle(items);
        iterator = items.iterator();
    }

    public boolean hasNext()
    {
        return (iterator.hasNext());
    }

    public T next()
    {
        return (iterator.next());
    }

    public void remove()
    {
        iterator.remove();
    }
}

Hashmap ne garantit pas que l'ordre de la carte restera constant dans le temps.

Ça n'a pas à l'être. La fonction de la touche d'une carte renvoie un ensemble et la méthode Iterator de l'ensemble le dit dans sa documentation:

"Renvoie un itérateur sur les éléments de cet ensemble. Les éléments sont renvoyés sans ordre particulier (sauf si cet ensemble est une instance d'une classe qui fournit une garantie)."

Donc, à moins que vous n'utilisiez l'une de ces classes avec une garantie, il n'y en a pas.

La carte est une interface et elle ne définit pas dans la documentation selon laquelle l'ordre doit être le même. Cela signifie que vous ne pouvez pas compter sur la commande. Mais si vous contrôlez l'implémentation de la carte renvoyée par GetMap (), vous pouvez utiliser LinkedHashmap ou Treemap et obtenir le même ordre de clés / valeurs tout le temps que vous les itérez.

Logiquement, si le contrat indique "aucune commande particulière n'est garantie", et puisque "l'ordre est sorti une fois" ordre particulier, alors la réponse est non, vous ne pouvez pas dépendre de la sortie de la même manière deux fois.

Je suis d'accord avec LinkedHashmap Thing. Je mets juste mes découvertes et mon expérience pendant que je fais face au problème quand j'essayais de trier Hashmap par Keys.

Mon code pour créer un hashmap:

HashMap<Integer, String> map;

@Before
public void initData() {
    map = new HashMap<>();

    map.put(55, "John");
    map.put(22, "Apple");
    map.put(66, "Earl");
    map.put(77, "Pearl");
    map.put(12, "George");
    map.put(6, "Rocky");

}

J'ai une fonction showmap qui imprime les entrées de la carte:

public void showMap (Map<Integer, String> map1) {
    for (Map.Entry<Integer,  String> entry: map1.entrySet()) {
        System.out.println("[Key: "+entry.getKey()+ " , "+"Value: "+entry.getValue() +"] ");

    }

}

Maintenant, lorsque j'imprime la carte avant de trier, il imprime la séquence suivante:

Map before sorting : 
[Key: 66 , Value: Earl] 
[Key: 22 , Value: Apple] 
[Key: 6 , Value: Rocky] 
[Key: 55 , Value: John] 
[Key: 12 , Value: George] 
[Key: 77 , Value: Pearl] 

Qui est fondamentalement différent de l'ordre dans lequel les clés de carte ont été mises.

Maintenant, quand je le trierai avec des clés de carte:

    List<Map.Entry<Integer, String>> entries = new ArrayList<>(map.entrySet());

    Collections.sort(entries, new Comparator<Entry<Integer, String>>() {

        @Override
        public int compare(Entry<Integer, String> o1, Entry<Integer, String> o2) {

            return o1.getKey().compareTo(o2.getKey());
        }
    });

    HashMap<Integer, String> sortedMap = new LinkedHashMap<>();

    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println("Putting key:"+entry.getKey());
        sortedMap.put(entry.getKey(), entry.getValue());
    }

    System.out.println("Map after sorting:");

    showMap(sortedMap);

La sortie est:

Sorting by keys : 
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 66 , Value: Earl] 
[Key: 6 , Value: Rocky] 
[Key: 22 , Value: Apple] 
[Key: 55 , Value: John] 
[Key: 12 , Value: George] 
[Key: 77 , Value: Pearl] 

Vous pouvez voir la différence par ordre de clés. L'ordre trié des clés est bien, mais celui des clés de la carte copiée est à nouveau dans le même ordre de la carte précédente. Je ne sais pas si cela est valable de dire, mais pour deux hashmap avec les mêmes clés, l'ordre des clés est le même. Cela implique la déclaration selon laquelle l'ordre des clés n'est pas garanti mais peut être le même pour deux cartes avec les mêmes clés en raison de la nature inhérente de l'algorithme d'insertion des clés si la mise en œuvre de HashMap de cette version JVM.

Maintenant, lorsque j'utilise LinkedHashMap pour copier des entrées triées sur Hashmap, je reçois le résultat souhaité (ce qui était naturel, mais ce n'est pas le point.

    HashMap<Integer, String> sortedMap = new LinkedHashMap<>();

    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println("Putting key:"+entry.getKey());
        sortedMap.put(entry.getKey(), entry.getValue());
    }

    System.out.println("Map after sorting:");

    showMap(sortedMap);

Production:

Sorting by keys : 
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 6 , Value: Rocky] 
[Key: 12 , Value: George] 
[Key: 22 , Value: Apple] 
[Key: 55 , Value: John] 
[Key: 66 , Value: Earl] 
[Key: 77 , Value: Pearl] 

Vous pouvez également stocker l'instance SET renvoyée par la méthode KeySet () et peut utiliser cette instance chaque fois que vous avez besoin du même ordre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top