Niedawno rozmawiam z kolegą na temat tego, jaki byłby optymalny sposób konwersji List
na Map
Javę i czy są jakieś szczególne korzyści z tego.
Chcę poznać optymalne podejście do konwersji i naprawdę docenię, jeśli ktoś może mnie poprowadzić.
Czy to dobre podejście:
List<Object[]> results;
Map<Integer, String> resultsMap = new HashMap<Integer, String>();
for (Object[] o : results) {
resultsMap.put((Integer) o[0], (String) o[1]);
}
Odpowiedzi:
Zakładając oczywiście, że każdy przedmiot ma
getKey()
metodę, która zwraca klucz odpowiedniego typu.źródło
getKey()
dowolny parametr?getKey()
było arbitralne.Z java-8, będziesz mógł to zrobić w jednym wierszu za pomocą strumieni i
Collectors
klasy.Krótkie demo:
Wynik:
Jak zauważono w komentarzach, możesz użyć
Function.identity()
zamiastitem -> item
, chociaż uważam, że jest toi -> i
dość wyraźne.Aby być kompletnym, pamiętaj, że możesz użyć operatora binarnego, jeśli twoja funkcja nie jest bijective. Rozważmy na przykład to
List
i funkcję mapowania, która dla wartości int oblicza wynik modulo 3:Podczas uruchamiania tego kodu pojawi się komunikat o błędzie
java.lang.IllegalStateException: Duplicate key 1
. Wynika to z faktu, że 1% 3 jest taki sam jak 4% 3, a zatem mają tę samą wartość klucza, biorąc pod uwagę funkcję mapowania klucza. W takim przypadku możesz podać operator scalania.Oto suma wartości;
(i1, i2) -> i1 + i2;
które można zastąpić referencją do metodyInteger::sum
.która teraz generuje:
Mam nadzieję, że to pomoże! :)
źródło
Function.identity()
zamiastitem -> item
Function.identity()
powracat -> t;
.::getKey
.Na wypadek, gdyby to pytanie nie zostało zamknięte jako duplikat, właściwą odpowiedzią jest skorzystanie z kolekcji Google :
źródło
Za pomocą Java 8 możesz wykonać następujące czynności:
Value
może być dowolnym obiektem, którego używasz.źródło
Od wersji Java 8 odpowiedź @ZouZou przy użyciu modułu
Collectors.toMap
zbierającego jest z pewnością idiomatycznym sposobem rozwiązania tego problemu.A ponieważ jest to tak częste zadanie, możemy przekształcić je w narzędzie statyczne.
W ten sposób rozwiązanie naprawdę staje się jednostronne.
A oto jak możesz go użyć na
List<Student>
:źródło
A
List
iMap
są koncepcyjnie różne. AList
to uporządkowana kolekcja przedmiotów. Elementy mogą zawierać duplikaty, a element może nie mieć pojęcia unikalnego identyfikatora (klucza). AMap
ma wartości odwzorowane na klucze. Każdy klucz może wskazywać tylko jedną wartość.Dlatego, w zależności od twoich
List
przedmiotów, może być lub może nie być możliwe przekonwertowanie go naMap
. Czy twojeList
przedmioty nie mają duplikatów? Czy każdy przedmiot ma unikalny klucz? Jeśli tak, to można umieścić je wMap
.źródło
Alexis opublikował już odpowiedź w Javie 8 przy użyciu metody
toMap(keyMapper, valueMapper)
. Zgodnie z dokumentacją dotyczącą implementacji tej metody:Jeśli więc jesteśmy zainteresowani konkretną implementacją
Map
interfejsu, np.HashMap
Możemy użyć przeciążonej formy jako:Chociaż użycie jednego
Function.identity()
lubi->i
jest w porządku, ale wydaje się, żeFunction.identity()
zamiasti -> i
może zaoszczędzić trochę pamięci zgodnie z tą pokrewną odpowiedzią .źródło
Istnieje również prosty sposób wykonania tego za pomocą Maps.uniqueIndex (...) od Googleguawa biblioteki
źródło
Metoda uniwersalna
źródło
converter
parametr w metodzie?Bez java-8 będziesz mógł to zrobić w jednej linii kolekcji Commons i klasy Closure
źródło
Przychodzi na myśl wiele rozwiązań, w zależności od tego, co chcesz osiągnąć:
Każdy element listy jest kluczem i wartością
Elementy listy mają coś do sprawdzenia, może nazwę:
Elementy listy mają coś, by je sprawdzić, i nie ma gwarancji, że są unikalne: użyj Googles MultiMaps
Nadanie wszystkim elementom pozycji jako klucza:
...
To naprawdę zależy od tego, co chcesz osiągnąć.
Jak widać na przykładach, Mapa jest mapowaniem klucza na wartość, podczas gdy lista jest tylko serią elementów mających pozycję. Więc po prostu nie są automatycznie konwertowalne.
źródło
Oto mała metoda, którą napisałem właśnie w tym celu. Korzysta z Validate z Apache Commons.
Możesz go używać.
źródło
Możesz wykorzystać API strumieniowe Java 8.
Więcej informacji na stronie: http://codecramp.com/java-8-streams-api-convert-list-map/
źródło
Przykład Java 8 do konwersji
List<?>
obiektów naMap<k, v>
:Kod skopiowany z:
https://www.mkyong.com/java8/java-8-convert-list-to-map/
źródło
jak już powiedziano, w java-8 mamy zwięzłe rozwiązanie Kolektorów:
a także można zagnieździć wiele grup, przekazując inną metodę groupingBy jako drugi parametr:
W ten sposób uzyskamy mapę wielopoziomową, taką jak ta:
Map<key, Map<key, List<Item>>>
źródło
Korzystanie ze strumieni java-8
źródło
Podoba mi się odpowiedź Kango_V, ale myślę, że jest zbyt skomplikowana. Myślę, że to jest prostsze - może zbyt proste. Jeśli jest pochylony, możesz zastąpić Łańcuch Generycznym znacznikiem i sprawić, by działał dla dowolnego typu Klucza.
Używany w ten sposób:
źródło
Apache Commons MapUtils.populateMap
Jeśli nie używasz Java 8 i z jakiegoś powodu nie chcesz używać jawnej pętli, spróbuj
MapUtils.populateMap
z Apache Commons.MapUtils.populateMap
Powiedz, że masz listę
Pair
s.A teraz chcesz mapę
Pair
klucza doPair
obiektu.daje wynik:
To powiedziawszy,
for
pętla może być łatwiejsza do zrozumienia. (To poniżej daje to samo wyjście):źródło