come ottenere una voce da hashmap senza iterare


172

Esiste un modo elegante per ottenerne solo uno Entry<K,V>da HashMap, senza iterare, se la chiave non è nota.

Dato che l'ordine di entrata non è importante, possiamo dire qualcosa del genere

hashMapObject.get(zeroth_index);

Anche se sono consapevole che non esiste un tale metodo di indice.

Se avessi provato l'approccio citato di seguito, sarebbe comunque necessario ottenere tutti i set di voci dell'hashmap .

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

Suggerimenti sono ben accetti

EDIT: si prega di suggerire qualsiasi altra struttura di dati a sufficienza requisito.

Risposte:


93

La risposta di Jesper è buona. Un'altra soluzione è utilizzare TreeMap (hai chiesto altre strutture di dati).

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

TreeMap ha un overhead, quindi HashMap è più veloce, ma solo come esempio di una soluzione alternativa.


O ConcurrentSkipListMap
Stephen Denne,

Per qualche motivo, il firstEntry()metodo non è definito nell'interfaccia SortedMapma solo in TreeMape ConcurrentSkipListMap:(
janko

1
firstEntry () è definito nell'interfaccia NavigableMap.
Per Östlund,

Ah, grazie, ho solo guardato SortedMapperché aveva il firstKey()metodo.
janko,

251

Le mappe non sono ordinate, quindi non esiste qualcosa come "la prima voce", ed è anche per questo che non esiste un metodo get-by-index su Map(o HashMap).

Potresti farlo:

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();

(Nota: controllo per una mappa vuota omessa).

Il tuo codice non ottiene tutte le voci nella mappa, ritorna immediatamente (ed esce dal ciclo) con la prima voce trovata.

Per stampare la chiave e il valore di questo primo elemento:

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

Nota: chiamare iterator()non significa che stai ripetendo l'intera mappa.


3
Solo una nota a LinkedHashMapmargine : mantiene le chiavi nell'ordine in cui sono state inserite.
Matthieu,

2
Sì, le mappe in generale non sono ordinate, ma alcune Mapimplementazioni come LinkedHashMape TreeMaphanno un ordine definito. ( HashMapno).
Jesper,

1
Risposta migliore della risposta scelta, poiché la risposta scelta utilizza TreeMap che prevede che la chiave sia di tipo Comparable.
Yazad,

28

Immagino che l'iteratore potrebbe essere la soluzione più semplice.

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

Un'altra soluzione (non carina):

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

O ancora (non meglio):

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

7
Non c'è motivo di usare la seconda o la terza versione. Il primo va benissimo, gli altri due perdono molto tempo fornendo un array / Elenco per niente.
Joachim Sauer,

4
Sono d'accordo, quindi i commenti "non belli" ;-)
cadrian,

14

Ottieni valori, convertilo in un array, ottieni il primo elemento dell'array:

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

W.


8

Perché vuoi evitare di chiamarlo entrySet()in genere non crea un oggetto completamente nuovo con il suo contesto, ma invece fornisce semplicemente un oggetto facciata. Parlare semplicemente entrySet()è un'operazione piuttosto economica.


8

Se stai usando Java 8, è semplice come findFirst () :

Esempio rapido:

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

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

6

Se vuoi davvero l'API che hai suggerito, puoi sottoclassare HashMap e tenere traccia delle chiavi in ​​un elenco, ad esempio. Non capisco davvero il punto, ma ti dà quello che vuoi. Se spieghi il caso d'uso previsto, forse possiamo trovare una soluzione migliore.

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: deliberatamente non ho approfondito il lato generici di questo ...


4

Cosa intendi con "senza iterare"?

Puoi usare map.entrySet().iterator().next()e non faresti scorrere la mappa (nel senso di "toccare ogni oggetto"). Entry<K, V>Tuttavia, non è possibile ottenere un senza utilizzare un iteratore. Il Javadoc di Map.Entry dice:

Il metodo Map.entrySet restituisce una vista raccolta della mappa, i cui elementi sono di questa classe. L'unico modo per ottenere un riferimento a una voce della mappa è dall'iteratore di questa vista raccolta. Questi oggetti Map.Entry sono validi solo per la durata dell'iterazione.

Puoi spiegare in modo più dettagliato cosa stai cercando di realizzare? Se si desidera gestire prima gli oggetti, che soddisfano un criterio specifico (come "avere una chiave particolare") e ripiegare sugli oggetti rimanenti in caso contrario, guardare a PriorityQueue . Ordinerà i tuoi oggetti in base all'ordine naturale o ad una definizione personalizzata Comparatorche fornisci.


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);
        }
    }
}

Questo approccio non funziona perché hai usato HashMap. Suppongo che usando LinkedHashMap sia la soluzione giusta in questo caso.


1
Quale metodo esiste in LinkedHashMap per far funzionare LinkedHashmap e questo codice no?
SL Barth - Ripristina Monica l'

3

Ciò otterrebbe una singola voce dalla mappa, che si avvicina il più vicino possibile, dato che "prima" non si applica davvero.

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);
        }
    }
}

2

Sono inciampato qui alla ricerca della stessa cosa ... Poi ho ricordato la Iterableslezione della biblioteca di Guava .

Per ottenere l'elemento "prima": Iterables.getFirst( someMap.values(), null );.
Sostanzialmente fa lo stesso di Map.values().iterator().next(), ma consente anche di specificare un valore predefinito (in questo caso null) nel caso in cui non ci fosse nulla nella mappa.

Iterables.getLast( someMap.values(), null ); restituisce l'ultimo elemento nella mappa.

Iterables.get( someMap.values(), 7, null ); restituisce il 7 ° elemento nella mappa se esiste, altrimenti un valore predefinito (in questo caso null).

Ricorda però che gli HashMap non sono ordinati ... quindi non aspettarti Iterables.getFirstdi restituire il primo oggetto che hai lanciato lì ... allo stesso modo Iterables.getLast. Forse utile per ottenere un valore mappato però.

Potrebbe non valere la pena aggiungere la libreria Guava proprio per questo, ma se ti capita di usare alcune delle altre fantastiche utility all'interno di quella libreria ...


1

Dopo il tuo EDIT, ecco il mio suggerimento:

Se hai una sola voce, puoi sostituire la mappa con un doppio oggetto. A seconda dei tipi e delle tue preferenze:

  • un array (di 2 valori, chiave e valore)
  • un oggetto semplice con due proprietà

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;

4
Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
Alex Riabov,

1
Sì, aggiungi qualche spiegazione insieme al tuo codice.
jkdev,

-3

Ho ottenuto la risposta: (È semplice)

Prendi una ArrayList e poi lanciala e trova le dimensioni dell'arraylist. Ecco qui :

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

Mostrerà la dimensione. (Dai un suggerimento). Sta funzionando.


2
In che modo questo ottiene un oggetto arbitrario da una mappa hash?
Colonnello trenta due
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.