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

172

Existe-t-il un moyen élégant d'en obtenir un seul à Entry<K,V>partir de HashMap, sans itération, 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 get by index.

Si j'essayais l'approche mentionnée ci-dessous, il faudrait toujours obtenir tout le jeu d'entrée de la 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 aux exigences.

nilesh
la source

Réponses:

93

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.

Per Östlund
la source
Ou ConcurrentSkipListMap
Stephen Denne
Pour une raison quelconque, la firstEntry()méthode n'est pas définie dans l'interface SortedMapmais uniquement dans TreeMapet ConcurrentSkipListMap:(
janko
1
firstEntry () est défini dans l'interface NavigableMap.
Per Östlund
Ah, merci, je n'ai regardé que SortedMapparce qu'il avait la firstKey()méthode.
janko
251

Les cartes ne sont pas ordonnées, il n'y a donc pas de «première entrée», et c'est aussi pourquoi il n'y a pas de méthode get-by-index sur Map(ou HashMap).

Vous pouvez 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 n'obtient 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: L'appel iterator()ne signifie pas que vous effectuez une itération sur toute la carte.

Jesper
la source
3
Juste une remarque: LinkedHashMapconserve les clés dans l'ordre dans lequel elles ont été insérées.
Matthieu
2
Oui, les cartes en général ne sont pas ordonnées, mais certaines Mapimplémentations telles que LinkedHashMapet TreeMapont un ordre défini. ( HashMapne fait pas).
Jesper
1
Meilleure réponse que la réponse choisie - puisque la réponse choisie utilise TreeMap qui s'attend à ce que la clé soit de type Comparable.
Yazad
28

Je suppose que l'itérateur est 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];
cadrien
la source
7
Il n'y a aucune raison d'utiliser la deuxième ou la troisième version. Le premier fonctionne parfaitement, les deux autres perdent beaucoup de temps à fournir un tableau / une liste pour rien.
Joachim Sauer
4
Je suis d'accord, d'où les commentaires "pas jolis" ;-)
cadrian
14

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

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

W.

Wiktor Misiek
la source
8

Pourquoi voulez-vous éviter de l'appeler entrySet()ne crée généralement pas un objet entièrement nouveau avec son propre contexte, mais fournit simplement un objet de façade. En termes simples, entrySet()c'est une opération assez bon marché.

Joachim Sauer
la source
8

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();
}
Cacho Santa
la source
6

Si vous voulez vraiment l'API que vous avez suggérée, vous pouvez sous-classer HashMap et garder une trace des clés dans une liste par exemple. Ne voyez pas vraiment l'intérêt de cela, mais cela vous donne ce que vous voulez. Si vous expliquez le cas d'utilisation prévu, nous pourrons 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 délibérément pas plongé dans le côté générique de cela ...

Adriaan Koster
la source
4

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

Vous pouvez utiliser map.entrySet().iterator().next()et ne pas parcourir la carte (dans le sens de "toucher chaque objet"). Entry<K, V>Cependant, vous ne pouvez pas mettre la main sur un sans utiliser un itérateur. Le Javadoc de Map.Entry dit:

La méthode Map.entrySet retourne une vue de collection de la carte, dont les éléments appartiennent à cette classe. La seule façon d'obtenir une référence à une entrée de carte est à partir de l'itérateur de cette vue de collection. Ces objets Map.Entry ne sont valides que pour la durée de l'itération.

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

janko
la source
4
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.

dmgcodevil
la source
1
Quelle méthode existe-t-il dans LinkedHashMap qui fait fonctionner LinkedHashmap, que ce code ne fait pas?
SL Barth - Réintègre Monica
3

Cela obtiendrait une seule entrée de la carte, ce qui est à peu près aussi proche 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);
        }
    }
}
Michael Easter
la source
2

Je suis tombé ici à la recherche de la même chose ... Je me suis alors souvenu de la Iterablesclasse de la bibliothèque Guava .

Pour obtenir l'élément « premier »: 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 carte s'il existe, sinon une valeur par défaut (dans ce cas nul).

Rappelez-vous cependant que les HashMaps ne sont pas commandés ... alors ne vous attendez pas Iterables.getFirstà renvoyer le premier élément que vous avez jeté là-dedans ... de même avec Iterables.getLast. Peut-être utile pour obtenir un valeur mappée.

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

SquidRott
la source
1

Suite à votre EDIT, 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
KLE
la source
0
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;
Vipul Vikram
la source
4
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
Alex Riabov
1
Oui, veuillez ajouter quelques explications avec votre code.
jkdev
-3

J'ai la réponse: (c'est simple)

Prenez une ArrayList puis lancez-la et trouvez la taille de l'arraylist. C'est ici :

    ArrayList count = new ArrayList();
    count=(ArrayList) maptabcolname.get("k1"); //here "k1" is Key
    System.out.println("number of elements="+count.size());

Il montrera la taille. (Donnez une suggestion). Ça marche.

Indranil Banerjee
la source
2
Comment cela obtient-il un élément arbitraire d'une carte de hachage?
Colonel Thirty Two du