Ist es möglich, ein Element anhand seiner Position aus HashMap abzurufen?

98

Wie kann man ein Element anhand seiner Position aus HashMap abrufen? Ist das überhaupt möglich?

Eugene
quelle
11
Was meinst du mit "Position"? HashMaps werden nicht bestellt, daher haben sie nicht die übliche Vorstellung von "Position", die Sie mit so etwas wie einem Vektor erhalten würden.
Mat
1
Meinen Sie damit die Einfügereihenfolge oder eine andere Reihenfolge?
Mark Elliot

Antworten:

93

HashMaps behält die Reihenfolge nicht bei:

Diese Klasse übernimmt keine Garantie für die Reihenfolge der Karte. Insbesondere kann nicht garantiert werden, dass die Bestellung über die Zeit konstant bleibt.

Schauen Sie sich LinkedHashMap an , das eine vorhersehbare Iterationsreihenfolge garantiert.

Wayne
quelle
16
Dies beantwortet die Frage nicht wirklich. Die anderen Antworten unten sind nützlicher.
Forresthopkinsa
6
In Bezug auf diese zitiert Dokumentation, die die Frage direkt beantwortet
Wayne
1
Selbst wenn die Reihenfolge über die Zeit nicht konstant ist, kann es dennoch möglich sein, eines der Mitglieder an einer bestimmten Position abzurufen.
Anfänger
Ich folge nicht. Erklären?
Wayne
Die HashMap-Verbindung ist unterbrochen / 404.
Raf
109

Verwenden Sie eine LinkedHashMap und konvertieren Sie die Werte in eine ArrayList, wenn Sie sie nach Position abrufen müssen.

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
quelle
2
Wird immer benötigt, um eine Kopie der Schlüssel von HashMap zu instanziieren?
Richard
Dadurch wird jedes Mal, wenn wir einen Wert abrufen, ein neues ArrayList-Objekt erstellt, was zu Speicherlecks führt
NullByte08
48

Wenn Sie die Reihenfolge beibehalten möchten, in der Sie die Elemente zur Karte hinzugefügt haben, verwenden Sie LinkedHashMapim Gegensatz zu nur HashMap.

Hier ist ein Ansatz, mit dem Sie einen Wert anhand seines Index in der Karte ermitteln können:

public Object getElementByIndex(LinkedHashMap map,int index){
    return map.get( (map.keySet().toArray())[ index ] );
}
Syd Lambert
quelle
1
Am einfachsten muss ich sagen ... Anstatt alles zu konvertieren, verwenden Sie nur das Keyset. Superb
kirtan403
19

Wenn Sie sich aus irgendeinem Grund an die HashMap halten müssen, können Sie das keySet in ein Array konvertieren und die Schlüssel im Array indizieren, um die Werte in der Map wie folgt zu erhalten:

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

Sie können dann wie folgt auf die Karte zugreifen:

map.get(keys[i]);
theNoble247
quelle
Beachten Sie, dass arr [i] geändert werden sollte in: keys [i]
Mohsen Abasi
Ok, ich habe Strings als Kartenschlüssel, um einen davon zu bekommen, wird der zweite Teil sein:String myKey = keys[i].toString();
Orici
12

Verwendung LinkedHashMap:

Implementierung der Hash-Tabelle und der verknüpften Liste der Map-Schnittstelle mit vorhersagbarer Iterationsreihenfolge. Diese Implementierung unterscheidet sich von HashMap dadurch, dass eine doppelt verknüpfte Liste geführt wird, die alle Einträge durchläuft.

ilalex
quelle
27
Dadurch bleibt die Reihenfolge erhalten, aber Sie können immer noch nicht über den Index auf Elemente zugreifen. Sie
müssten
Dieser Link verweist auf eine alte Version der API. Ich würde vorschlagen, auf eine Java 6 oder 7 API zu verlinken.
jzd
6

Verwenden Sie LinkedHashMap und verwenden Sie diese Funktion.

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

Definieren Sie so und.

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

Die Funktion kann den ausgewählten Eintrag zurückgeben.

Jeff Lee
quelle
3

Ich gehe davon aus, dass Sie sich mit 'Position' auf die Reihenfolge beziehen, in der Sie die Elemente in die HashMap eingefügt haben. In diesem Fall möchten Sie eine LinkedHashMap verwenden. Die LinkedHashMap bietet jedoch keine Zugriffsmethode. Sie müssen eine wie schreiben

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

Ein anderer Arbeitsansatz besteht darin, Kartenwerte in ein Array umzuwandeln und dann das Element am Index abzurufen. Der Testlauf von 100 000 Elementen durch Indexsuche in LinkedHashMap von 100 000 Objekten unter Verwendung der folgenden Ansätze führte zu folgenden Ergebnissen:

//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

Alles in allem scheint das Abrufen von Elementen per Index aus LinkedHashMap eine ziemlich schwere Operation zu sein.

user3738243
quelle
2

HashMap - und die zugrunde liegende Datenstruktur - Hash-Tabellen haben keine Vorstellung von Position. Im Gegensatz zu einer LinkedList oder einem Vektor wird der Eingabeschlüssel in einen 'Bucket' umgewandelt, in dem der Wert gespeichert wird. Diese Buckets sind nicht in einer Weise angeordnet, die außerhalb der HashMap-Schnittstelle sinnvoll ist. Daher sind die Elemente, die Sie in die HashMap einfügen, nicht in dem Sinne angeordnet, wie Sie es von den anderen Datenstrukturen erwarten würden

dfb
quelle
2

HashMap hat kein Positionskonzept, daher gibt es keine Möglichkeit, ein Objekt nach Position zu ermitteln. Objekte in Karten werden gesetzt und über Schlüssel abgerufen.

Robby Pond
quelle
2

Sie können den folgenden Code verwenden, um den Schlüssel zu erhalten: String [] keys = (String[]) item.keySet().toArray(new String[0]);

und erhalten Sie ein Objekt oder eine Liste, die mit dem Schlüssel dieses Elements wie folgt in HashMap eingefügt werden: item.get(keys[position]);

mahsa k
quelle
2

Standardmäßig unterstützt Java LinkedHasMap das Abrufen von Werten nach Position nicht. Also schlage ich vor, mit maßgeschneiderten zu gehenIndexedLinkedHashMap

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

Dann können Sie diese angepasste LinkedHasMap als verwenden

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

Werte hinzufügen

indexedLinkedHashMap.add("key1",UserModel);

Um den Wert nach Index zu erhalten

indexedLinkedHashMap.getItemByIndex(position);
Vikram Kodag
quelle
1

HashMaps erlauben keinen Zugriff nach Position, kennen nur den Hash-Code und können den Wert abrufen, wenn sie den Hash-Code des Schlüssels berechnen können. TreeMaps haben einen Begriff der Bestellung. Linkedhas-Karten behalten die Reihenfolge bei, in der sie in die Karte eingegeben wurden.

fastcodejava
quelle
0

Sie können versuchen, so etwas zu implementieren. Schauen Sie sich Folgendes an:

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

Ich hoffe das funktioniert bei dir.

Francisco Javier Ocampo
quelle