Est-il possible d'obtenir un élément de HashMap par sa position?

99

Comment récupérer un élément de HashMap par sa position, est-ce possible du tout?

Eugène
la source
11
Qu'entendez-vous par «position»? Les HashMaps ne sont pas ordonnés, donc ils n'ont pas la notion habituelle de "position" que vous obtiendriez avec quelque chose comme un Vector.
Mat
1
Voulez-vous dire par son ordre d'insertion ou un autre ordre?
Mark Elliot

Réponses:

94

Les HashMaps ne conservent pas l'ordre:

Cette classe ne donne aucune garantie quant à l'ordre de la carte; en particulier, il ne garantit pas que l'ordre restera constant dans le temps.

Jetez un œil à LinkedHashMap , qui garantit un ordre d'itération prévisible.

Wayne
la source
16
Cela ne répond pas vraiment à la question. Les autres réponses ci-dessous sont plus utiles.
forresthopkinsa
6
Avec égards, cela cite une documentation qui répond directement à la question
Wayne
1
Même si l'ordre n'est pas constant dans le temps, il pourrait toujours être possible de récupérer l'un des membres par une position donnée.
Débutant le
Je ne suis pas. Explique?
Wayne
Le lien HashMap est rompu / 404.
Raf
111

Utilisez un LinkedHashMap et lorsque vous avez besoin de récupérer par position, convertissez les valeurs en ArrayList.

LinkedHashMap<String,String> linkedHashMap = new LinkedHashMap<String,String>();
/* Populate */
linkedHashMap.put("key0","value0");
linkedHashMap.put("key1","value1");
linkedHashMap.put("key2","value2");
/* Get by position */
int pos = 1;
String value = (new ArrayList<String>(linkedHashMap.values())).get(pos);
Kulnor
la source
2
Est toujours nécessaire pour instancier une copie des clés de HashMap ??
Richard
cela créera un nouvel objet ArrayList à chaque fois que nous récupérons la valeur, ce qui entraînera des fuites de mémoire
NullByte08
48

Si vous souhaitez conserver l'ordre dans lequel vous avez ajouté les éléments à la carte, utilisez LinkedHashMapplutôt que juste HashMap.

Voici une approche qui vous permettra d'obtenir une valeur par son index dans la carte:

public Object getElementByIndex(LinkedHashMap map,int index){
    return map.get( (map.keySet().toArray())[ index ] );
}
Syd Lambert
la source
1
Le plus simple, je dois dire ... Au lieu de tout convertir, vous n'utilisez que des clés. Superbe
kirtan403
19

Si, pour une raison quelconque, vous devez vous en tenir à hashMap, vous pouvez convertir le keySet en tableau et indexer les clés du tableau pour obtenir les valeurs de la carte comme ceci:

Object[] keys = map.keySet().toArray();

Vous pouvez ensuite accéder à la carte comme:

map.get(keys[i]);
theNoble247
la source
Notez que arr [i] doit être remplacé par: keys [i]
Mohsen Abasi
Ok, j'ai des chaînes comme clés de carte, pour en obtenir une, la deuxième partie sera:String myKey = keys[i].toString();
Orici
12

Utilisez LinkedHashMap:

Implémentation de table de hachage et de liste liée de l'interface Map, avec ordre d'itération prévisible. Cette implémentation diffère de HashMap en ce qu'elle maintient une liste à double lien parcourant toutes ses entrées.

ilalex
la source
27
cela conservera l'ordre, mais vous ne pourrez toujours pas accéder aux éléments par leur index. Vous auriez à itérer
Bozho
ce lien est vers une ancienne version de l'API. Je suggérerais de créer un lien vers une API Java 6 ou 7.
jzd
6

Utilisez LinkedHashMap et utilisez cette fonction.

private LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();

Définissez comme ceci et.

private Entry getEntry(int id){
        Iterator iterator = map.entrySet().iterator();
        int n = 0;
        while(iterator.hasNext()){
            Entry entry = (Entry) iterator.next();
            if(n == id){
                return entry;
            }
            n ++;
        }
        return null;
    }

La fonction peut renvoyer l'entrée sélectionnée.

Jeff Lee
la source
3

Je suppose que par «position», vous faites référence à l'ordre dans lequel vous avez inséré les éléments dans le HashMap. Dans ce cas, vous souhaitez utiliser un LinkedHashMap. Le LinkedHashMap n'offre cependant pas de méthode d'accesseur; vous devrez en écrire un comme

public Object getElementAt(LinkedHashMap map, int index) {
    for (Map.Entry entry : map.entrySet()) {
        if (index-- == 0) {
            return entry.value();
        }
    }
    return null;
}
homebrew
la source
3

Une autre approche de travail consiste à transformer les valeurs de la carte en un tableau, puis à récupérer l'élément à l'index. Un test de 100 000 éléments par recherche d'index dans LinkedHashMap de 100 000 objets utilisant les approches suivantes a conduit aux résultats suivants:

//My answer:
public Particle getElementByIndex(LinkedHashMap<Point, Particle> map,int index){
    return map.values().toArray(new Particle[map.values().size()])[index];
} //68 965 ms

//Syd Lambert's answer:
public Particle getElementByIndex(LinkedHashMap<Point, Particle> map,int index){
    return map.get( (map.keySet().toArray())[ index ] );
} //80 700 ms

Dans l'ensemble, récupérer un élément par index à partir de LinkedHashMap semble être une opération assez lourde.

utilisateur3738243
la source
2

HashMap - et la structure de données sous-jacente - les tables de hachage, n'ont pas de notion de position. Contrairement à LinkedList ou Vector, la clé d'entrée est transformée en un «compartiment» où la valeur est stockée. Ces compartiments ne sont pas classés d'une manière qui a du sens en dehors de l'interface HashMap et, en tant que tels, les éléments que vous mettez dans le HashMap ne sont pas dans l'ordre dans le sens que vous attendez avec les autres structures de données

dfb
la source
2

HashMap n'a pas de concept de position, il n'y a donc aucun moyen d'obtenir un objet par position. Les objets dans Maps sont définis et récupérés par clés.

Robby Pond
la source
2

vous pouvez utiliser le code ci-dessous pour obtenir la clé: String [] keys = (String[]) item.keySet().toArray(new String[0]);

et obtenez un objet ou une liste qui s'insèrent dans HashMap avec la clé de cet élément comme ceci: item.get(keys[position]);

mahsa k
la source
2

Par défaut, java LinkedHasMap ne prend pas en charge l'obtention de valeur par position. Je suggère donc d'aller avec personnaliséIndexedLinkedHashMap

public class IndexedLinkedHashMap<K, V> extends LinkedHashMap<K, V> {

    private ArrayList<K> keysList = new ArrayList<>();

    public void add(K key, V val) {
        super.put(key, val);
        keysList.add(key);
    }

    public void update(K key, V val) {
        super.put(key, val);
    }

    public void removeItemByKey(K key) {
        super.remove(key);
        keysList.remove(key);
    }

    public void removeItemByIndex(int index) {
        super.remove(keysList.get(index));
        keysList.remove(index);
    }

    public V getItemByIndex(int i) {
        return (V) super.get(keysList.get(i));
    }

    public int getIndexByKey(K key) {
        return keysList.indexOf(key);
    }
}

Ensuite, vous pouvez utiliser cette LinkedHasMap personnalisée comme

IndexedLinkedHashMap<String,UserModel> indexedLinkedHashMap=new IndexedLinkedHashMap<>();

POUR ajouter des valeurs

indexedLinkedHashMap.add("key1",UserModel);

Pour obtenir la valeur par index

indexedLinkedHashMap.getItemByIndex(position);
Vikram Kodag
la source
1

Les HashMaps n'autorisent pas l'accès par position, il ne connaît que le code de hachage et il peut récupérer la valeur s'il peut calculer le code de hachage de la clé. Les TreeMaps ont une notion d'ordre. Les cartes Linkedhas conservent l'ordre dans lequel elles sont entrées sur la carte.

fastcodejava
la source
0

Vous pouvez essayer d'implémenter quelque chose comme ça, regardez:

Map<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("juan", 2);
map.put("pedro", 3);
map.put("pablo", 5);
map.put("iphoncio",9)

List<String> indexes = new ArrayList<String>(map.keySet()); // <== Parse

System.out.println(indexes.indexOf("juan"));     // ==> 0
System.out.println(indexes.indexOf("iphoncio"));      // ==> 3

J'espère que cela fonctionne pour vous.

Francisco Javier Ocampo
la source