Czy można pobrać element z HashMap na podstawie jego pozycji?

99

Jak pobrać element z HashMap według jego pozycji, czy to w ogóle możliwe?

Eugene
źródło
11
Co masz na myśli mówiąc „stanowisko”? HashMapy nie są uporządkowane, więc nie mają zwykłego pojęcia „pozycji”, które można uzyskać za pomocą czegoś takiego jak Vector.
Mat
1
Czy masz na myśli jego kolejność reklamową czy inną kolejność?
Mark Elliot

Odpowiedzi:

94

HashMapy nie zachowują kolejności:

Ta klasa nie gwarantuje kolejności map; w szczególności nie gwarantuje, że zamówienie pozostanie niezmienne w czasie.

Spójrz na LinkedHashMap , który gwarantuje przewidywalną kolejność iteracji.

Wayne
źródło
16
To naprawdę nie odpowiada na pytanie. Inne odpowiedzi poniżej są bardziej przydatne.
forresthopkinsa
6
Z całym szacunkiem cytuję dokumentację, która bezpośrednio odpowiada na pytanie
Wayne
1
Nawet jeśli kolejność nie jest stała w czasie, nadal istnieje możliwość pobrania jednego z członków na dane stanowisko.
Początkujący
Nie nadążam. Wyjaśnić?
Wayne,
Link HashMap jest uszkodzony / 404.
Raf
110

Użyj LinkedHashMap, a gdy chcesz pobrać według pozycji, przekonwertuj wartości na ArrayList.

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
źródło
2
Zawsze jest potrzebne do utworzenia kopii kluczy z HashMap ??
Richard
spowoduje to utworzenie nowego obiektu ArrayList za każdym razem, gdy pobieramy wartość, co prowadzi do wycieków pamięci
NullByte08
48

Jeśli chcesz zachować kolejność, w jakiej dodałeś elementy do mapy, użyj LinkedHashMapzamiast just HashMap.

Oto podejście, które pozwoli Ci uzyskać wartość na podstawie jej indeksu na mapie:

public Object getElementByIndex(LinkedHashMap map,int index){
    return map.get( (map.keySet().toArray())[ index ] );
}
Syd Lambert
źródło
1
Najprościej muszę powiedzieć ... Zamiast konwertować wszystko, używasz tylko zestawu kluczy. Znakomity
kirtan403
19

Jeśli z jakiegoś powodu musisz trzymać się hashMap, możesz przekonwertować zestaw kluczy na tablicę i zindeksować klucze w tablicy, aby uzyskać wartości z mapy w następujący sposób:

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

Możesz wtedy uzyskać dostęp do mapy, na przykład:

map.get(keys[i]);
theNoble247
źródło
Zauważ, że arr [i] należy zmienić na: keys [i]
Mohsen Abasi
Ok, mam Strings jako klawisze mapy, żeby dostać jeden z nich, druga część to:String myKey = keys[i].toString();
Orici
12

Zastosowanie LinkedHashMap:

Implementacja tabeli skrótów i połączonych list interfejsu Map z przewidywalną kolejnością iteracji. Ta implementacja różni się od HashMap tym, że utrzymuje podwójnie połączoną listę obejmującą wszystkie jej wpisy.

ilalex
źródło
27
To pozwoli zachować kolejność, ale nadal nie możesz uzyskać dostępu do elementów za pomocą ich indeksu. Musiałbyś iterować
Bozho
to łącze prowadzi do starej wersji interfejsu API. Sugerowałbym linkowanie do API Java 6 lub 7.
jzd
6

Użyj LinkedHashMap i użyj tej funkcji.

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

Zdefiniuj w ten sposób i.

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

Funkcja może zwrócić wybrany wpis.

Jeff Lee
źródło
3

Zakładam, że przez „pozycję” masz na myśli kolejność, w której wstawiłeś elementy do HashMap. W takim przypadku chcesz używać LinkedHashMap. Jednak LinkedHashMap nie oferuje metody dostępu; będziesz musiał napisać jedno polubienie

public Object getElementAt(LinkedHashMap map, int index) {
    for (Map.Entry entry : map.entrySet()) {
        if (index-- == 0) {
            return entry.value();
        }
    }
    return null;
}
homebrew
źródło
3

Innym działającym podejściem jest przekształcenie wartości mapy w tablicę, a następnie pobranie elementu w indeksie. Uruchomienie testowe 100 000 elementów przy wyszukiwaniu indeksu w LinkedHashMap obejmującym 100 000 obiektów przy użyciu następujących podejść doprowadziło do następujących wyników:

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

Podsumowując, pobieranie elementu po indeksie z LinkedHashMap wydaje się być dość ciężką operacją.

user3738243
źródło
2

HashMap - i podstawowa struktura danych - tabele skrótów, nie mają pojęcia pozycji. W przeciwieństwie do LinkedList lub Vector klucz wejściowy jest przekształcany w „zasobnik”, w którym przechowywana jest wartość. Te zasobniki nie są uporządkowane w sposób, który ma sens poza interfejsem HashMap i jako takie, elementy, które umieszczasz w HashMap nie są w takim sensie, jakiego można by się spodziewać po innych strukturach danych

dfb
źródło
2

HashMap nie ma pojęcia pozycji, więc nie ma możliwości uzyskania obiektu według pozycji. Obiekty w Mapach są ustawiane i pobierane za pomocą kluczy.

Robby Pond
źródło
2

możesz użyć poniższego kodu, aby uzyskać klucz: String [] keys = (String[]) item.keySet().toArray(new String[0]);

i pobierz obiekt lub listę, która wstawia do HashMap z kluczem tego elementu: item.get(keys[position]);

mahsa k
źródło
2

Domyślnie java LinkedHasMap nie obsługuje pobierania wartości według pozycji. Więc proponuję wybrać dostosowaneIndexedLinkedHashMap

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

Następnie możesz użyć tej dostosowanej LinkedHasMap jako

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

Aby dodać wartości

indexedLinkedHashMap.add("key1",UserModel);

Aby uzyskać wartość według indeksu

indexedLinkedHashMap.getItemByIndex(position);
Vikram Kodag
źródło
1

HashMaps nie zezwala na dostęp według pozycji, wie tylko o kodzie skrótu i ​​może pobrać wartość, jeśli może obliczyć kod skrótu klucza. TreeMaps ma pojęcie porządkowania. Mapy w serwisie Linkedhas zachowują kolejność, w jakiej zostały wprowadzone na mapę.

fastcodejava
źródło
0

Możesz spróbować zaimplementować coś takiego, spójrz na:

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

Mam nadzieję, że to działa dla Ciebie.

Francisco Javier Ocampo
źródło