SparseArray vs HashMap

Mogę wymyślić kilka powodów, dla których HashMap S z liczbami całkowitymi są znacznie lepsze niż SparseArray s:

  1. dokumentacja Androida dla SparseArray mówi " ogólnie jest wolniejszy niż tradycyjny HashMap".
  2. jeśli piszesz kod używając HashMap s zamiast SparseArray S, Twój kod będzie działał z innymi implementacjami Map i będziesz mógł używać wszystkich API Javy zaprojektowanych dla map.
  3. jeśli napiszesz kod używając HashMap s zamiast SparseArrayS Twój kod będzie działał w innych systemach niż android projekty.
  4. nadpisuje equals() i hashCode() podczas gdy SparseArray Nie.

Jednak za każdym razem, gdy próbuję użyć {[0] } z liczbami całkowitymi w projekcie Androida, IntelliJ mówi mi, że powinienem zamiast tego użyć SparseArray. Trudno mi to zrozumieć. Czy ktoś zna jakieś istotne powody używania SparseArray s?

Author: Sebastian, 2014-08-29

7 answers

SparseArray Może być używany do wymiany HashMap kiedy klucz jest prymitywny. Istnieje kilka wariantów dla różnych typów kluczy/wartości, chociaż nie wszystkie z nich są publicznie dostępne.

Korzyści to:

  • bez przydziału
  • No boxing

Wady:

  • ogólnie wolniejsze, nie wskazane dla dużych zbiorów
  • Nie będą działać w Projekcie non-Android]}

HashMap może być zastąpiony przez po:

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 

Jeśli chodzi o pamięć, oto przykład SparseIntArray vs HashMap<Integer, Integer> dla 1000 elementów:

SparseIntArray:

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

Class = 12 + 3 * 4 = 24 bajty
Array = 20 + 1000 * 4 = 4024 bajtów
Razem = 8,072 bajtów

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 bajtów
Wpis = 32 + 16 + 16 = 64 bajty
Array = 20 + 1000 * 64 = 64024 bajtów
Razem = 64 136 bajtów

Źródło: Android Memories by Romain Guy z slide 90.

Powyższe liczby to ilość pamięci (w bajtach) przydzielona na stercie przez JVM. Mogą się one różnić w zależności od konkretnego zastosowanego JVM.

Pakiet java.lang.instrument zawiera kilka pomocnych metod dla zaawansowanych operacji, takich jak sprawdzanie rozmiaru obiektu za pomocą getObjectSize(Object objectToSize).

Dodatkowe informacje są dostępne w oficjalnej dokumentacji Oracle .

Class = 12 bajtów + (N zmiennych instancji) * 4 bajty
Array = 20 bajtów + (n elements) * (Rozmiar elementu)
Wpis = 32 bajty + (1. Rozmiar elementu) + (2. Rozmiar elementu)

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-18 21:01:55

Jednak za każdym razem, gdy próbuję użyć Hashmapy z kluczami całkowitymi w Androidzie projekt, intelliJ mówi mi, że powinienem użyć SparseArray zamiast.

Jest to tylko ostrzeżenie z tej dokumentacji z niej:

Ma być bardziej wydajny w pamięci niż używanie Hashmapy do Mapa liczb całkowitych do obiektów

SparseArrayjest wykonana tak, aby była efektywna pamięciowo niż użycie zwykłej Hashmapy, czyli nie pozwala na wielokrotne przerwy w tablica nie jak HashMap. Nie ma się czym martwić możesz użyć tradycyjnej Hashmapy, jeśli nie chcesz martwić się o przydział pamięci do urządzenia.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-24 14:56:02

Przyszedłem tu po prostu chcąc przykład jak używać SparseArray. Jest to odpowiedź uzupełniająca na to pytanie.

Utwórz SparseArray

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

A SparseArray mapuje liczby całkowite do niektórych Object, więc możesz zastąpić String w powyższym przykładzie dowolnym innym Object. Jeśli mapujesz liczby całkowite na liczby całkowite, użyj SparseIntArray.

Dodaj lub zaktualizuj elementy

Użycie put (lub append) aby dodać elementy do tablicy.

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

Uwaga że klucze int nie muszą być w porządku. Można to również wykorzystać do zmiany wartości w konkretnym kluczu int.

Usuń elementy

Użycie remove (lub delete) aby usunąć elementy z tablicy.

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

Parametr int jest kluczem całkowitym.

Wyszukiwanie wartości dla klucza int

Użycie get aby uzyskać wartość dla jakiegoś klucza integer.

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

Możesz użyć get(int key, E valueIfKeyNotFound) jeśli chcesz uniknąć uzyskania null za brakujące klucze.

Iteracja elementów

Możesz użyć keyAt oraz valueAt niektóre indeksy do pętli przez kolekcję, ponieważ SparseArray utrzymuje oddzielny indeks różniący się od kluczy 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

Zwróć uwagę, że klucze są uporządkowane rosnąco, a nie w kolejności, w jakiej zostały dodane.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-21 20:12:54

Rzadka tablica w Javie jest strukturą danych, która mapuje Klucze do wartości. Ten sam pomysł co Mapa, ale inna realizacja:

  1. Mapa jest reprezentowana wewnętrznie jako tablica list, gdzie każdy element w tych listach jest parą kluczy, wartości. Zarówno klucz, jak i wartość są instancjami obiektu.

  2. Sparse array składa się po prostu z dwóch tablic: tablicy kluczy (pierwotnych) i tablicy wartości (obiektów). W tych tablicach mogą występować luki, stąd termin "sparse" array.

Głównym interesem sparsearray jest to, że zapisuje pamięć poprzez użycie prymitywów zamiast obiektów jako klucza.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-04 08:13:45

Po jakimś googlowaniu staram się dodać trochę informacji do już zamieszczonych anwers:

Isaac Taylor zrobił porównanie wydajności dla SparseArrays i Hashmaps. Stwierdza, że

Hashmap i sparsearray są bardzo podobne do struktury danych Rozmiary poniżej 1000

I

Gdy rozmiar został zwiększony do znaku 10 000 [...] Hashmap ma większą wydajność przy dodawaniu obiektów, natomiast sparsearray ma greater wydajność podczas pobierania obiektów. [...] Przy wielkości 100 000 [...] Hashmap bardzo szybko traci wydajność

Porównanie na Edgblog pokazuje, że SparseArray potrzebuje znacznie mniej pamięci niż HashMap ze względu na mniejszy klucz (int vs Integer) i fakt, że

A HashMap.Instancja wejściowa musi śledzić odniesienia do klucz, wartość i następny wpis. Plus musi również przechowywać hash wpisu jako int.

As wniosek powiedziałbym, że różnica może mieć znaczenie, jeśli zamierzasz przechowywać wiele danych na mapie. W przeciwnym razie zignoruj Ostrzeżenie.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-12 18:57:12

Dokumentacja Androida dla sparsearraya mówi: "ogólnie jest wolniej niż tradycyjna Hashmapa".

Tak, to prawda. Ale gdy masz tylko 10 lub 20 elementów, różnica w wydajności powinna być znikoma.

Jeśli piszesz kod za pomocą HashMaps, a nie SparseArrays swój kod będzie współpracować z innymi implementacjami Map i będziesz mógł używaj wszystkich interfejsów API java zaprojektowanych dla map

Myślę, że najczęściej używamy tylko HashMap aby wyszukać wartość związaną z kluczem, podczas gdy SparseArray jest w tym naprawdę dobry.

Jeśli piszesz kod za pomocą HashMaps, a nie SparseArrays swój kod będzie działać w projektach innych niż android.

Kod źródłowy SparseArray jest dość prosty i łatwy do zrozumienia, więc płacisz tylko trochę wysiłku przenosząc go na inne platformy(poprzez prostą Kopiuj i wklej).

Mapa nadpisuje equals () i hashCode (), podczas gdy SparseArray Nie

All I można powiedzieć, (do większości deweloperów)kogo to obchodzi?

Innym ważnym aspektem SparseArray jest to, że używa tablicy do przechowywania wszystkich elementów, podczas gdy HashMap używa Entry, więc SparseArray kosztuje znacznie mniej pamięci niż HashMap, zobacz to

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-29 02:29:26

Szkoda, że kompilator wystawia Ostrzeżenie. Domyślam się, że HashMap został nadużyty do przechowywania przedmiotów.

Sparsearray mają swoje miejsce. Biorąc pod uwagę, że używają binarnego algorytmu wyszukiwania, aby znaleźć wartość w tablicy, musisz wziąć pod uwagę, co robisz. Binarne Wyszukiwanie to o (log n), podczas gdy hash lookup to O(1). Nie musi to oznaczać, że wyszukiwanie binarne jest wolniejsze dla danego zestawu danych. Jednak wraz ze wzrostem liczby wpisów, moc tabeli hash przejmuje kontrolę. Stąd komentarze, w których mała liczba wpisów może być równa i prawdopodobnie lepsza niż użycie Hashmapy.

HashMap jest tylko tak dobry jak hash i może mieć wpływ na współczynnik obciążenia(myślę, że w późniejszych wersjach ignorują współczynnik obciążenia, więc można go lepiej zoptymalizować). Dodali również dodatkowy hash, aby upewnić się, że hash jest dobry. Również powód, dla którego SparseArray działa naprawdę dobrze dla stosunkowo niewielu wpisów (

Sugerowałbym, że jeśli potrzebujesz tabeli hash i chcesz lepiej wykorzystanie pamięci dla prymitywnej liczby całkowitej (bez auto boksu), itd., wypróbuj trove. ( http://trove.starlight-systems.com - licencja LGPL). (Brak powiązań z trove, podobnie jak ich biblioteka)

Dzięki uproszczonemu budynkowi multi-dex, który mamy, nie musisz nawet przepakowywać skarbca na to, czego potrzebujesz. (trove ma wiele klas)

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-02 22:00:09