¿Es posible obtener un elemento de HashMap por su posición?

99

¿Cómo recuperar un elemento de HashMap por su posición, es posible en absoluto?

Eugenio
fuente
11
¿Qué quieres decir con "posición"? Los HashMaps no están ordenados, por lo que no tienen la noción habitual de "posición" que obtendría con algo como un Vector.
Mat
1
¿Te refieres a su orden de inserción o alguna otra orden?
Mark Elliot

Respuestas:

94

Los HashMaps no conservan el orden:

Esta clase no garantiza el orden del mapa; en particular, no garantiza que el pedido se mantenga constante en el tiempo.

Eche un vistazo a LinkedHashMap , que garantiza un orden de iteración predecible.

Wayne
fuente
16
Esto realmente no responde a la pregunta. Las otras respuestas a continuación son más útiles.
forresthopkinsa
6
Con respeto, esto cita documentación que responde directamente a la pregunta
Wayne
1
Incluso si el orden no es constante en el tiempo, aún podría ser posible recuperar uno de los miembros por una posición determinada.
Principiante
Yo no sigo. ¿Explique?
Wayne
El enlace HashMap está roto / 404.
Raf
109

Use un LinkedHashMap y cuando necesite recuperar por posición, convierta los valores en un 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
fuente
2
¿Siempre es necesario crear una instancia de las claves de HashMap?
Richard
esto creará un nuevo objeto ArrayList cada vez que recuperemos un valor, lo que
provocará
48

Si desea mantener el orden en el que agregó los elementos al mapa, utilice LinkedHashMapen lugar de solo HashMap.

Aquí hay un enfoque que le permitirá obtener un valor por su índice en el mapa:

public Object getElementByIndex(LinkedHashMap map,int index){
    return map.get( (map.keySet().toArray())[ index ] );
}
Syd Lambert
fuente
1
Lo más simple debo decir ... En lugar de convertir todo, está utilizando solo un conjunto de claves. Excelente
kirtan403
19

Si, por alguna razón, tiene que seguir con el hashMap, puede convertir el conjunto de claves en una matriz e indexar las claves en la matriz para obtener los valores en el mapa de la siguiente manera:

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

Luego puede acceder al mapa como:

map.get(keys[i]);
theNoble247
fuente
Tenga en cuenta que arr [i] debe cambiarse a: claves [i]
Mohsen Abasi
Ok, tengo cadenas como claves de mapa, para obtener una de ellas, la segunda parte será:String myKey = keys[i].toString();
Orici
12

Utilizar LinkedHashMap:

Implementación de tabla hash y lista enlazada de la interfaz Map, con orden de iteración predecible. Esta implementación se diferencia de HashMap en que mantiene una lista doblemente vinculada que se ejecuta a través de todas sus entradas.

ilalex
fuente
27
eso mantendrá el orden, pero aún no puede acceder a los elementos por su índice. Tendrías que iterar
Bozho
este enlace es a una versión antigua de la API. Sugeriría vincular a una API de Java 6 o 7.
jzd
6

Use LinkedHashMap y use esta función.

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

Defina así y.

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

La función puede devolver la entrada seleccionada.

Jeff Lee
fuente
3

Supongo que por "posición" se refiere al orden en el que ha insertado los elementos en el HashMap. En ese caso, desea utilizar un LinkedHashMap. Sin embargo, LinkedHashMap no ofrece un método de acceso; tendrás que escribir uno como

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

Otro enfoque de trabajo es transformar los valores del mapa en una matriz y luego recuperar el elemento en el índice. La ejecución de prueba de 100.000 búsquedas de elementos por índice en LinkedHashMap de 100.000 objetos utilizando los siguientes enfoques condujo a los siguientes resultados:

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

En general, recuperar elemento por índice de LinkedHashMap parece ser una operación bastante pesada.

usuario3738243
fuente
2

HashMap, y la estructura de datos subyacente, las tablas hash no tienen una noción de posición. A diferencia de LinkedList o Vector, la clave de entrada se transforma en un 'depósito' donde se almacena el valor. Estos depósitos no están ordenados de una manera que tenga sentido fuera de la interfaz de HashMap y, como tal, los elementos que colocas en el HashMap no están en orden en el sentido que esperarías con las otras estructuras de datos.

dfb
fuente
2

HashMap no tiene un concepto de posición, por lo que no hay forma de obtener un objeto por posición. Los objetos en Mapas se configuran y obtienen mediante claves.

Estanque de Robby
fuente
2

puede usar el siguiente código para obtener la clave: String [] keys = (String[]) item.keySet().toArray(new String[0]);

y obtenga el objeto o lista que se inserta en HashMap con la clave de este elemento de esta manera: item.get(keys[position]);

mahsa k
fuente
2

De forma predeterminada, java LinkedHasMap no admite la obtención de valor por posición. Así que sugiero ir con personalizadoIndexedLinkedHashMap

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

Entonces puede usar este LinkedHasMap personalizado como

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

PARA agregar valores

indexedLinkedHashMap.add("key1",UserModel);

Obtener valor por índice

indexedLinkedHashMap.getItemByIndex(position);
Vikram Kodag
fuente
1

HashMaps no permite el acceso por posición, solo conoce el código hash y puede recuperar el valor si puede calcular el código hash de la clave. TreeMaps tiene la noción de ordenar. Los mapas de Linkedhas conservan el orden en el que ingresaron al mapa.

fastcodejava
fuente
0

Puedes intentar implementar algo así, mira:

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

Espero que esto funcione para ti.

Francisco Javier Ocampo
fuente