wie man den einen Eintrag von der Hashmap erhält, ohne zu iterieren


172

Gibt es eine elegante Möglichkeit, nur eine Entry<K,V>von HashMap zu erhalten, ohne zu iterieren, wenn der Schlüssel nicht bekannt ist?

Da die Reihenfolge der Einreise nicht wichtig ist, können wir so etwas sagen

hashMapObject.get(zeroth_index);

Obwohl mir bewusst ist, dass es keine solche Get-by-Index-Methode gibt.

Wenn ich den unten erwähnten Ansatz ausprobieren würde , müsste immer noch der gesamte Eintragssatz der Hashmap abgerufen werden .

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

Vorschläge sind willkommen.

BEARBEITEN: Bitte schlagen Sie eine andere Datenstruktur vor, um die Anforderungen zu erfüllen.

Antworten:


93

Die Antwort von Jesper ist gut. Eine andere Lösung ist die Verwendung von TreeMap (Sie haben nach anderen Datenstrukturen gefragt).

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

TreeMap hat einen Overhead, sodass HashMap schneller ist, aber nur als Beispiel für eine alternative Lösung.


Oder ConcurrentSkipListMap
Stephen Denne

Aus irgendeinem Grund ist die firstEntry()Methode nicht in der Schnittstelle definiert, SortedMapsondern nur in TreeMapund ConcurrentSkipListMap:(
janko

1
firstEntry () ist in der NavigableMap-Oberfläche definiert.
Per Östlund

Ah, danke, ich habe nur geschaut, SortedMapweil es die firstKey()Methode hatte.
Janko

251

Karten sind nicht geordnet, daher gibt es keinen "ersten Eintrag", und deshalb gibt es auch keine Methode zum Ermitteln des Index für Map(oder HashMap).

Sie könnten dies tun:

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

(Hinweis: Die Suche nach einer leeren Karte wurde weggelassen.)

Ihr Code erhält nicht alle Einträge in der Karte, sondern kehrt sofort mit dem ersten gefundenen Eintrag zurück (und bricht aus der Schleife aus).

So drucken Sie den Schlüssel und den Wert dieses ersten Elements:

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

Hinweis: Aufrufen iterator()bedeutet nicht, dass Sie die gesamte Karte durchlaufen.


3
Nur eine Randnotiz: LinkedHashMapHält die Schlüssel in der Reihenfolge, in der sie eingefügt wurden.
Matthieu

2
Ja, Karten werden im Allgemeinen nicht geordnet, aber einige MapImplementierungen wie LinkedHashMapund TreeMaphaben eine definierte Reihenfolge. ( HashMapnicht).
Jesper

1
Bessere Antwort als die gewählte Antwort - da die gewählte Antwort TreeMap verwendet, das erwartet, dass der Schlüssel vom Typ Vergleichbar ist.
Yazad

28

Ich denke, der Iterator ist möglicherweise die einfachste Lösung.

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

Eine andere Lösung (nicht schön):

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

Oder doch (nicht besser):

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

7
Es gibt keinen Grund, die zweite oder dritte Version zu verwenden. Der erste ist vollkommen in Ordnung, die anderen beiden verschwenden viel Zeit, indem sie ein Array / eine Liste für nichts bereitstellen.
Joachim Sauer

4
Ich stimme zu, daher die "nicht hübschen" Kommentare ;-)
Cadrian

14

Werte abrufen, in ein Array konvertieren, erstes Element des Arrays abrufen:

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

W.


8

Warum wollen Sie vermeiden wollen , rufen entrySet()sie nicht nicht generell ein völlig neues Objekt mit seinem eigenen Kontext zu schaffen, sondern liefern nur eine Fassade Objekt. Einfach gesagt entrySet()ist eine ziemlich billige Operation.


8

Wenn Sie Java 8 verwenden, ist dies so einfach wie findFirst () :

Kurzes Beispiel:

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

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

6

Wenn Sie die von Ihnen vorgeschlagene API wirklich möchten, können Sie HashMap unterordnen und beispielsweise die Schlüssel in einer Liste verfolgen. Sehen Sie den Punkt darin nicht wirklich, aber es gibt Ihnen, was Sie wollen. Wenn Sie den beabsichtigten Anwendungsfall erläutern, können wir möglicherweise eine bessere Lösung finden.

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: Ich habe mich bewusst nicht mit der generischen Seite befasst ...


4

Was meinst du mit "ohne Iteration"?

Sie können die map.entrySet().iterator().next()Karte verwenden und würden sie nicht durchlaufen (im Sinne von "Berühren jedes Objekts"). Sie können jedoch keinen erreichen, Entry<K, V>ohne einen Iterator zu verwenden. Der Javadoc von Map.Entry sagt:

Die Map.entrySet-Methode gibt eine Sammlungsansicht der Karte zurück, deren Elemente zu dieser Klasse gehören. Die einzige Möglichkeit, einen Verweis auf einen Karteneintrag zu erhalten, ist der Iterator dieser Sammlungsansicht. Diese Map.Entry-Objekte sind nur für die Dauer der Iteration gültig.

Können Sie genauer erklären, was Sie erreichen wollen? Wenn Sie zuerst Objekte behandeln möchten, die einem bestimmten Kriterium entsprechen (z. B. "einen bestimmten Schlüssel haben") und ansonsten auf die verbleibenden Objekte zurückgreifen möchten, sehen Sie sich eine PriorityQueue an . Es ordnet Ihre Objekte basierend auf der natürlichen Reihenfolge oder einer von ComparatorIhnen angegebenen benutzerdefinierten Reihenfolge .


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

Dieser Ansatz funktioniert nicht, da Sie HashMap verwendet haben. Ich gehe davon aus, dass die Verwendung von LinkedHashMap in diesem Fall die richtige Lösung ist.


1
Welche Methode in LinkedHashMap sorgt dafür, dass LinkedHashmap funktioniert, was dieser Code nicht tut?
SL Barth - Wiedereinsetzung Monica

3

Dies würde einen einzelnen Eintrag von der Karte erhalten, der ungefähr so ​​nah wie möglich ist, da "zuerst" nicht wirklich zutrifft.

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

Stolperte hier auf der Suche nach dem gleichen ... Ich erinnerte mich dann an die IterablesKlasse aus der Guavenbibliothek .

So erhalten Sie das "erste" Element : Iterables.getFirst( someMap.values(), null );.
Im Wesentlichen das Gleiche wie Map.values().iterator().next(), aber Sie können auch einen Standardwert (in diesem Fall null) angeben, falls die Karte nichts enthält.

Iterables.getLast( someMap.values(), null ); Gibt das letzte Element in der Karte zurück.

Iterables.get( someMap.values(), 7, null ); Gibt das 7. Element in der Map zurück, falls vorhanden, andernfalls einen Standardwert (in diesem Fall null).

Denken Sie jedoch daran, dass HashMaps nicht bestellt werden. Erwarten Sie also nicht, dass Sie Iterables.getFirstden ersten Artikel zurückgeben, den Sie dort hineingeworfen haben ... ebenfalls mit Iterables.getLast. Vielleicht nützlich, um einen zugeordneten Wert zu erhalten.

Es lohnt sich vielleicht nicht, die Guava-Bibliothek dafür hinzuzufügen, aber wenn Sie zufällig einige der anderen coolen Dienstprogramme in dieser Bibliothek verwenden ...


1

Nach Ihrer Bearbeitung ist hier mein Vorschlag:

Wenn Sie nur einen Eintrag haben, können Sie die Karte durch ein Doppelobjekt ersetzen. Abhängig von den Typen und Ihren Vorlieben:

  • ein Array (mit 2 Werten, Schlüssel und Wert)
  • ein einfaches Objekt mit zwei Eigenschaften

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
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Alex Riabov

1
Ja, bitte fügen Sie Ihrem Code eine Erklärung hinzu.
jkdev

-3

Ich habe die Antwort bekommen: (Es ist einfach)

Nehmen Sie eine ArrayList, setzen Sie sie um und ermitteln Sie die Größe der Arrayliste. Hier ist es :

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

Es wird die Größe angezeigt. (Vorschlag machen). Es funktioniert.


2
Wie erhält man ein beliebiges Element aus einer Hash-Map?
Oberst
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.