SparseArray vs HashMap


Se me ocurren varias razones por las que HashMap s con claves enteras son mucho mejores que SparseArray s:

  1. La documentación de Android para un SparseArray dice "Generalmente es más lento que un HashMap tradicional".
  2. Si escribe código usando HashMaps en lugar de SparseArrays, su código funcionará con otras implementaciones de Map y podrá usar todas las API de Java diseñadas para Maps.
  3. Si escribes código usando HashMap s en lugar de SparseArray s, tu código funcionará en dispositivos no android proyecto.
  4. El mapa anula equals() y hashCode() mientras que SparseArray no lo hace.

Sin embargo, cada vez que intento usar un HashMap con claves enteras en un proyecto Android, IntelliJ me dice que debería usar un SparseArray en su lugar. Encuentro esto muy difícil de entender. ¿Alguien conoce alguna razón convincente para usar SparseArray s?

Author: Sebastian, 2014-08-29

7 answers

SparseArray se puede utilizar para reemplazar HashMap cuando la clave es un tipo primitivo. Hay algunas variantes para diferentes tipos de clave / valor, aunque no todas están disponibles públicamente.

Los beneficios son:

  • Libre de asignación
  • No boxeo

Inconvenientes:

  • Generalmente más lento, no indicado para colecciones grandes
  • No funcionarán en un proyecto que no sea Android

HashMap puede ser reemplazado por el siguiente:

SparseArray          <Integer, Object>
SparseBooleanArray   <Integer, Boolean>
SparseIntArray       <Integer, Integer>
SparseLongArray      <Integer, Long>
LongSparseArray      <Long, Object>
LongSparseLongArray  <Long, Long>   //this is not a public class                                 
                                    //but can be copied from  Android source code 

En términos de memoria, aquí hay un ejemplo de SparseIntArray vs HashMap<Integer, Integer> para 1000 elementos:

SparseIntArray:

class SparseIntArray {
    int[] keys;
    int[] values;
    int size;
}

Class = 12 + 3 * 4 = 24 bytes
Array = 20 + 1000 * 4 = 4024 bytes
Total = 8.072 bytes

HashMap:

class HashMap<K, V> {
    Entry<K, V>[] table;
    Entry<K, V> forNull;
    int size;
    int modCount;
    int threshold;
    Set<K> keys
    Set<Entry<K, V>> entries;
    Collection<V> values;
}

Class = 12 + 8 * 4 = 48 bytes
Entrada = 32 + 16 + 16 = 64 bytes
Array = 20 + 1000 * 64 = 64024 bytes
Total = 64.136 bytes

Fuente: Android Memories by Romain Guy de la diapositiva 90.

Los números anteriores son la cantidad de memoria (en bytes) asignada en el montón por JVM. Pueden variar dependiendo de la JVM específica utilizada.

El paquete java.lang.instrument contiene algunos métodos útiles para operaciones avanzadas como comprobar el tamaño de un objeto con getObjectSize(Object objectToSize).

La información adicional está disponible en la documentación oficial de Oracle .

Class = 12 bytes + (n variables de instancia) * 4 bytes
Matriz = 20 bytes + (n elementos) * (tamaño del elemento)
Entry = 32 bytes + (1st element size) + (2nd element size)

 170
Author: Sarpe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-18 21:01:55

Sin embargo, cada vez que intento usar un HashMap con claves enteras en un Android proyecto, IntelliJ me dice que debería usar un SparseArray en su lugar.

Es solo una advertencia de esta documentación de su matriz dispersa:

Se pretende que sea más eficiente en memoria que usar un HashMap para asignar enteros a Objetos

El SparseArray se hace para ser memoria eficiente que el uso del HashMap regular, es decir, no permite múltiples espacios dentro la matriz no como HashMap. No hay nada de qué preocuparse puede usar el HashMap tradicional si desea no preocuparse por la asignación de memoria al dispositivo.

 17
Author: Rod_Algonquin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-24 14:56:02

Vine aquí solo queriendo un ejemplo de cómo usar SparseArray. Esta es una respuesta complementaria para eso.

Crear un SparseArray

SparseArray<String> sparseArray = new SparseArray<>();

A SparseArray asigna enteros a algún Object, por lo que podría reemplazar String en el ejemplo anterior con cualquier otro Object. Si está asignando enteros a enteros, utilice SparseIntArray.

Añadir o actualizar elementos

Uso put (o append) para agregar elementos a la matriz.

sparseArray.put(10, "horse");
sparseArray.put(3, "cow");
sparseArray.put(1, "camel");
sparseArray.put(99, "sheep");
sparseArray.put(30, "goat");
sparseArray.put(17, "pig");

Nota que las teclas int no necesitan estar en orden. Esto también se puede usar para cambiar el valor en una clave int particular.

Eliminar elementos

Uso remove (o delete) para eliminar elementos de la matriz.

sparseArray.remove(17); // "pig" removed

El parámetro int es la clave entera.

Valores de búsqueda para una clave int

Uso get para obtener el valor de un número entero clave.

String someAnimal = sparseArray.get(99);  // "sheep"
String anotherAnimal = sparseArray.get(200); // null

Puede utilizar get(int key, E valueIfKeyNotFound) si usted quiere evitar llegar null para las claves que faltan.

Iterar sobre los elementos

Puede utilizar keyAt y valueAt algún índice para recorrer la colección porque el SparseArray mantiene un índice separado distinto de las claves int.

int size = sparseArray.size();
for (int i = 0; i < size; i++) {

    int key = sparseArray.keyAt(i);
    String value = sparseArray.valueAt(i);

    Log.i("TAG", "key: " + key + " value: " + value);
}

// key: 1 value: camel
// key: 3 value: cow
// key: 10 value: horse
// key: 30 value: goat
// key: 99 value: sheep

Tenga en cuenta que las claves están ordenadas en valor ascendente, no en el orden en que se agregaron.

 12
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-21 20:12:54

Una matriz dispersa en Java es una estructura de datos que asigna claves a valores. La misma idea que un Mapa, pero diferente implementación:

  1. Un mapa se representa internamente como una matriz de listas, donde cada elemento de estas listas es una clave,par de valores. Tanto la clave como el valor son instancias de objetos.

  2. Una matriz dispersa se compone simplemente de dos matrices: una matriz de claves (primitivas) y una matriz de valores (objetos). Puede haber lagunas en estos índices de matrices, de ahí el término matriz "escasa".

El principal interés del SparseArray es que ahorra memoria usando primitivas en lugar de objetos como clave.

 8
Author: Ganesh Katikar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-04 08:13:45

Después de buscar en Google, intento agregar algo de información a los anwers ya publicados:

Isaac Taylor hizo una comparación de rendimiento para SparseArrays y Hashmaps. Afirma que[1]}

El Hashmap y el SparseArray son muy similares para la estructura de datos tamaños inferiores a 1.000

Y

Cuando el tamaño se ha aumentado a la marca de 10.000 [...] el Hashmap tiene un mayor rendimiento con la adición de objetos, mientras que el SparseArray tiene mayor rendimiento al recuperar objetos. [...] At a size of 100,000 [...] el Hashmap pierde rendimiento muy rápidamente

Una comparación en Edgblog muestra que un SparseArray necesita mucha menos memoria que un HashMap debido a la clave más pequeña (int vs Integer) y el hecho de que

Un HashMap.La instancia de entrada debe realizar un seguimiento de las referencias clave, el valor y la siguiente entrada. Además, también necesita almacenar el hash de la entrada como int.

As una conclusión Diría que la diferencia podría importar si va a almacenar una gran cantidad de datos en su Mapa. De lo contrario, simplemente ignore la advertencia.

 8
Author: Sebastian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-12 18:57:12

La documentación de Android para un SparseArray dice " Es generalmente más lento que un HashMap tradicional".

Sí,es correcto. Pero cuando solo tiene 10 o 20 elementos, la diferencia de rendimiento debe ser insignificante.

Si escribe código usando HashMaps en lugar de SparseArrays, su código trabajará con otras implementaciones de Map y usted será capaz de utilice todas las API de Java diseñadas para Maps

Creo que la mayoría de las veces solo usamos HashMap buscar un valor asociado a una clave mientras que SparseArray es realmente bueno en esto.

Si escribe código usando HashMaps en lugar de SparseArrays, su código funcionará en proyectos no android.

El código fuente de SparseArray es bastante simple y fácil de entender, por lo que solo paga poco esfuerzo al moverlo a otras plataformas(a través de un simple COPY&Paste).

Map overrides equals () and hashCode () whereas SparseArray doesn't

Todo I puede decir es, (a la mayoría de los desarrolladores) que se preocupan?

Otro aspecto importante de SparseArray es que solo usa una matriz para almacenar todos los elementos mientras que HashMap usa Entry, por lo que SparseArray cuesta significativamente menos memoria que un HashMap, vea este

 2
Author: suitianshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-29 02:29:26

Es desafortunado que el compilador emita una advertencia. Supongo que HashMap se ha utilizado demasiado para almacenar elementos.

Los SparseArrays tienen su lugar. Dado que utilizan un algoritmo de búsqueda binario para encontrar un valor en una matriz, debe considerar lo que está haciendo. La búsqueda binaria es O (log n) mientras que la búsqueda hash es O(1). Esto no significa necesariamente que la búsqueda binaria sea más lenta para un conjunto de datos dado. Sin embargo, a medida que el número de entradas crece, el poder de la tabla hash toma el control. Ahí los comentarios donde el número bajo de entradas puede ser igual y posiblemente mejor que usar un HashMap.

Un HashMap es tan bueno como el hash y también puede verse afectado por el factor de carga (creo que en versiones posteriores ignoran el factor de carga para que pueda optimizarse mejor). También agregaron un hachís secundario para asegurarse de que el hachís sea bueno. También la razón SparseArray funciona muy bien para relativamente pocas entradas (

Te sugeriría que si necesitas una tabla hash y quieres algo mejor uso de memoria para enteros primitivos (sin boxeo automático), etc., prueba trove. ( http://trove.starlight-systems.com - Licencia LGPL). (Sin afiliación con trove, al igual que su biblioteca)

Con la construcción simplificada multi-dex que tenemos, ni siquiera necesita volver a empaquetar trove para lo que necesita. (trove tiene muchas clases)

 1
Author: Bruce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-02 22:00:09