web-dev-qa-db-fra.com

comment obtenir une entrée de hashmap sans itérer

Existe-t-il un moyen élégant d’obtenir un seul Entry<K,V> auprès de HashMap, sans itérer, si la clé n’est pas connue?.

Comme l’ordre d’entrée n’est pas important, pouvons-nous dire quelque chose comme:

hashMapObject.get(zeroth_index);

Bien que je sache qu’il n’existe pas de méthode d’obtention par index.

Si j'essayais l'approche mentionnée ci-dessous, il faudrait tout de même obtenir tout le jeu d'entrées du hashmap .

for(Map.Entry<String, String> entry : MapObj.entrySet()) {
    return entry;
}

Les suggestions sont les bienvenues.

EDIT: Veuillez suggérer toute autre structure de données pour répondre à vos besoins.

153
nilesh

La réponse de Jesper est bonne. Une autre solution consiste à utiliser TreeMap (vous avez demandé d'autres structures de données).

TreeMap<String, String> myMap = new TreeMap<String, String>();
String first = myMap.firstEntry().getValue();
String firstOther = myMap.get(myMap.firstKey());

TreeMap a une surcharge donc HashMap est plus rapide, mais juste comme exemple d'une solution alternative.

89
Per Östlund

Les cartes n'étant pas ordonnées, la «première entrée» n'existe pas. C'est pourquoi il n'existe pas de méthode d'obtention d'index sur Map (ou HashMap).

Vous pourriez faire ceci:

Map<String, String> map = ...;  // wherever you get this from

// Get the first entry that the iterator returns
Map.Entry<String, String> entry = map.entrySet().iterator().next();

(Remarque: la recherche d'une carte vide est omise).

Votre code ne reçoit pas toutes les entrées de la carte, il retourne immédiatement (et sort de la boucle) avec la première entrée trouvée.

Pour imprimer la clé et la valeur de ce premier élément:

System.out.println("Key: "+entry.getKey()+", Value: "+entry.getValue());

Remarque: appeler iterator() ne signifie pas que vous effectuez une itération sur l'ensemble de la carte.

237
Jesper

Je suppose que l'itérateur peut être la solution la plus simple.

return hashMapObject.entrySet().iterator().next();

Une autre solution (pas jolie):

return new ArrayList(hashMapObject.entrySet()).get(0);

Ou encore (pas mieux):

return hashMapObject.entrySet().toArray()[0];
28
cadrian

Obtenez les valeurs, convertissez-le en tableau, obtenez le premier élément du tableau:

map.values().toArray()[0]

W.

13
Wiktor Misiek

Pourquoi voulez-vous éviter d’appeler entrySet()? Il crée pas généralement un objet entièrement nouveau avec son propre contexte, mais fournit simplement un objet de façade. Parler simplement entrySet() est une opération assez bon marché.

8
Joachim Sauer

Si vous utilisez Java 8, c'est aussi simple que findFirst () :

Exemple rapide:

Optional<Car> theCarFoundOpt = carMap.values().stream().findFirst();

if(theCarFoundOpt.isPresent()) {
    return theCarFoundOpt.get().startEngine();
}
6
Cacho Santa

Si vous voulez vraiment l'API que vous avez suggérée, vous pouvez sous-classer HashMap et suivre les clés dans une liste par exemple. Ne voyez pas le point là-dedans, mais cela vous donne ce que vous voulez. Si vous expliquez le cas d'utilisation prévu, nous pourrions peut-être trouver une meilleure solution.

import Java.util.ArrayList;
import Java.util.HashMap;
import Java.util.List;
import Java.util.Map;

@SuppressWarnings("unchecked")
public class IndexedMap extends HashMap {

    private List<Object> keyIndex;

    public IndexedMap() {
        keyIndex = new ArrayList<Object>();
    }

    /**
     * Returns the key at the specified position in this Map's keyIndex.
     * 
     * @param index
     *            index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException
     *             if the index is out of range (index < 0 || index >= size())
     */
    public Object get(int index) {
        return keyIndex.get(index);
    }

    @Override
    public Object put(Object key, Object value) {

        addKeyToIndex(key);
        return super.put(key, value);
    }

    @Override
    public void putAll(Map source) {

        for (Object key : source.keySet()) {
            addKeyToIndex(key);
        }
        super.putAll(source);
    }

    private void addKeyToIndex(Object key) {

        if (!keyIndex.contains(key)) {
            keyIndex.add(key);
        }
    }

    @Override
    public Object remove(Object key) {

        keyIndex.remove(key);
        return super.remove(key);
    }
}

EDIT: Je n'ai pas délibérément approfondi le côté générique de cette ...

6
Adriaan Koster

Que voulez-vous dire par "sans itérer"?

Vous pouvez utiliser map.entrySet().iterator().next() et vous ne voudriez pas parcourir la carte (au sens de "toucher chaque objet"). Vous ne pouvez pas vous procurer un Entry<K, V> sans utiliser un itérateur. La Javadoc de Map.Entry dit:

La méthode Map.entrySet retourne un collection-view de la carte, dont les éléments sont de cette classe. Le seul moyen d'obtenir une référence à une carte l'entrée vient de l'itérateur de cette collection-view. Ces Map.Entry les objets ne sont valables que pour le durée de l'itération.

Pouvez-vous expliquer plus en détail ce que vous essayez d'accomplir? Si vous voulez d'abord manipuler des objets qui correspondent à un critère spécifique (comme "avoir une clé particulière") et revenir aux objets restants, regardez un PriorityQueue . Il ordonnera vos objets en fonction de l'ordre naturel ou d'une Comparator personnalisée que vous fournissez.

4
janko
import Java.util.*;

public class Friday {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("code", 10);
        map.put("to", 11);
        map.put("joy", 12);

        if (! map.isEmpty()) {
            Map.Entry<String, Integer> entry = map.entrySet().iterator().next();
            System.out.println(entry);
        }
    }
}

Cette approche ne fonctionne pas car vous avez utilisé HashMap. Je suppose que l'utilisation de LinkedHashMap sera la bonne solution dans ce cas.

4
dmgcodevil

Cela donnerait une entrée unique sur la carte, ce qui correspond à peu près autant que possible, étant donné que «premier» ne s'applique pas vraiment.

import Java.util.*;

public class Friday {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("code", 10);
        map.put("to", 11);
        map.put("joy", 12);

        if (! map.isEmpty()) {
            Map.Entry<String, Integer> entry = map.entrySet().iterator().next();
            System.out.println(entry);
        }
    }
}
3
Michael Easter

Je suis tombé par hasard ici à la recherche de la même chose ... Je me suis alors rappelé la classe Iterables de la bibliothèque de goyave .

Pour obtenir le "premier" élément: Iterables.getFirst( someMap.values(), null );
Fait essentiellement la même chose que Map.values().iterator().next(), mais vous permet également de spécifier une valeur par défaut (dans ce cas null) s'il n'y a rien dans la carte.

Iterables.getLast( someMap.values(), null ); renvoie le dernier élément de la carte.

Iterables.get( someMap.values(), 7, null ); renvoie le 7ème élément de la mappe s'il existe, sinon une valeur par défaut (null dans ce cas).

Rappelez-vous cependant que les HashMaps ne sont pas commandées ... ne vous attendez donc pas à ce que Iterables.getFirst renvoie le premier élément que vous avez jeté là-bas ... de même avec Iterables.getLast. Peut-être utile d'obtenir une valeur mappée cependant.

Cela ne vaut peut-être pas la peine d'ajouter la bibliothèque Guava pour cela, mais si vous utilisez certains des utilitaires intéressants de cette bibliothèque ...

2
SquidRott

Après votre modification, voici ma suggestion:

Si vous n'avez qu'une seule entrée, vous pouvez remplacer la carte par un objet double . Selon les types et vos préférences:

  • un tableau (de 2 valeurs, clé et valeur)
  • un objet simple avec deux propriétés
1
KLE
map<string,string>m;
auto it=m.begin();//get iterator to the first element of map(m)
return m->first;//return first string(1st string in map<string,string>m)
//Incase you want the second string 
//you can use return m->second(2st string in map<string,string>m)
//if you want to iterate the whole map you can use loop
for(auto it:m)//m is a map
   cout<<it->first<<endl;
0
Vipul Vikram