Ich möchte eine Liste von Objekten mit Java 8-Streams und Lambdas in eine Map übersetzen.
So würde ich es in Java 7 und darunter schreiben.
private Map<String, Choice> nameMap(List<Choice> choices) {
final Map<String, Choice> hashMap = new HashMap<>();
for (final Choice choice : choices) {
hashMap.put(choice.getName(), choice);
}
return hashMap;
}
Ich kann dies leicht mit Java 8 und Guava erreichen, aber ich würde gerne wissen, wie man dies ohne Guava macht.
In Guave:
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, new Function<Choice, String>() {
@Override
public String apply(final Choice input) {
return input.getName();
}
});
}
Und Guava mit Java 8-Lambdas.
private Map<String, Choice> nameMap(List<Choice> choices) {
return Maps.uniqueIndex(choices, Choice::getName);
}
Basierend auf Collectors
Dokumentation es ist so einfach wie:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName,
Function.identity()));
Wenn Ihr SchlüsselNICHTgarantiert eindeutig für alle Elemente in der Liste ist, sollten Sie ihn in einen Map<String, List<Choice>>
anstelle eines Map<String, Choice>
konvertieren.
Map<String, List<Choice>> result =
choices.stream().collect(Collectors.groupingBy(Choice::getName));
Verwenden Sie getName () als Schlüssel und die Auswahl selbst als Wert der Map:
Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
Hier ist eine weitere, falls Sie Collectors.toMap () nicht verwenden möchten
Map<String, Choice> result =
choices.stream().collect(HashMap<String, Choice>::new,
(m, c) -> m.put(c.getName(), c),
(m, u) -> {});
Bei den meisten Antworten wird ein Fall nicht angezeigt, wenn die Liste doppelte Elemente enthält . In diesem Fall wird IllegalStateException
ausgegeben. Siehe den folgenden Code, um List-Duplikate zu behandeln ebenso:
public Map<String, Choice> convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName, choice -> choice,
(oldValue, newValue) -> newValue));
}
Eine weitere Option auf einfache Weise
Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));
Wenn Sie zum Beispiel Objektfelder in eine Map konvertieren möchten:
Beispielobjekt:
class Item{
private String code;
private String name;
public Item(String code, String name) {
this.code = code;
this.name = name;
}
//getters and setters
}
Und Vorgang konvertieren List To Map:
List<Item> list = new ArrayList<>();
list.add(new Item("code1", "name1"));
list.add(new Item("code2", "name2"));
Map<String,String> map = list.stream()
.collect(Collectors.toMap(Item::getCode, Item::getName));
Wenn Sie sich nicht für die Verwendung von Drittanbieter-Bibliotheken interessieren, verfügt AOLs cyclops-react -Lib (Offenlegung, dass ich einen Beitrag geleistet habe) über Erweiterungen für alle JDK Collection -Typen, einschließlich List und Map .
ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);
Ich habe versucht, dies zu tun, und fand heraus, dass ich bei Verwendung der Antworten oben bei der Verwendung von Functions.identity()
für den Schlüssel der Map dann Probleme mit der Verwendung einer lokalen Methode wie this::localMethodName
hatte, die aufgrund von Tippproblemen tatsächlich funktioniert.
Functions.identity()
macht in diesem Fall tatsächlich etwas mit der Typisierung, so dass die Methode nur funktioniert, indem Object
zurückgegeben und ein Parameter von Object
akzeptiert wird.
Um dieses Problem zu lösen, habe ich Functions.identity()
eingestellt und stattdessen s->s
verwendet.
Also, mein Code, in meinem Fall, um alle Verzeichnisse in einem Verzeichnis aufzulisten, und für jedes Verzeichnis den Namen des Verzeichnisses als Schlüssel für die Map verwenden und dann eine Methode mit dem Verzeichnisnamen aufrufen und eine Sammlung von Elementen zurückgeben, sieht folgendermaßen aus:
Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));
Sie können einen Stream der Indizes mit einem IntStream erstellen und dann in eine Map konvertieren:
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
Ich werde schreiben, wie man die Liste in eine Map umwandelt, indem man generics und die Inversion von control verwendet. Einfach universelle Methode!
Vielleicht Wir haben Liste von Ganzzahlen oder Liste von Objekten. Die Frage ist also: Was sollte der Schlüssel der Karte sein?
schnittstelle erstellen
public interface KeyFinder<K, E> {
K getKey(E e);
}
jetzt mit Umkehrung der Kontrolle:
static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> Finder) {
return list.stream().collect(Collectors.toMap(e -> Finder.getKey(e) , e -> e));
}
Wenn wir beispielsweise Objekte eines Buches haben, wählt diese Klasse den Schlüssel für die Karte
public class BookKeyFinder implements KeyFinder<Long, Book> {
@Override
public Long getKey(Book e) {
return e.getPrice()
}
}
Ich benutze diese Syntax
Map<Integer, List<Choice>> choiceMap =
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
.toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));
Hierfür können Streams verwendet werden. Um die Notwendigkeit der expliziten Verwendung von Collectors
zu beseitigen, ist es möglich, toMap
statisch zu importieren (wie von Effective Java empfohlen, dritte Ausgabe).
import static Java.util.stream.Collectors.toMap;
private static Map<String, Choice> nameMap(List<Choice> choices) {
return choices.stream().collect(toMap(Choice::getName, it -> it));
}
Hier ist die Lösung von StreamEx
StreamEx.of(choices).toMap(Choice::getName, c -> c);
Dies kann auf zwei Arten erfolgen. Lassen Sie die Person die Klasse sein, mit der wir sie demonstrieren werden.
public class Person {
private String name;
private int age;
public String getAge() {
return age;
}
}
Lassen Sie Personen die Liste der Personen sein, die in die Karte umgewandelt werden sollen
1.Verwenden Sie einfach foreach und einen Lambda-Ausdruck in der Liste
Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));
2.Verwenden von Collectors-Streams, die in der angegebenen Liste definiert sind.
Map<Integer,List<Person>> mapPersons =
persons.stream().collect(Collectors.groupingBy(Person::getAge));
List<V> choices; // your list
Map<K,V> result = choices.stream().collect(Collectors.toMap(choice::getKey(),choice));
//assuming class "V" has a method to get the key, this method must handle case of duplicates too and provide a unique key.
String array[] = {"ASDFASDFASDF","AA", "BBB", "CCCC", "DD", "EEDDDAD"};
List<String> list = Arrays.asList(array);
Map<Integer, String> map = list.stream()
.collect(Collectors.toMap(s -> s.length(), s -> s, (x, y) -> {
System.out.println("Dublicate key" + x);
return x;
},()-> new TreeMap<>((s1,s2)->s2.compareTo(s1))));
System.out.println(map);
Den Schlüssel AA {12 = ASDFASDFASDF, 7 = EEDDDAD, 4 = CCCC, 3 = BBB, 2 = AA}
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));
Sogar diesen Zweck dient für mich,
Map<String,Choice> map= list1.stream().collect(()-> new HashMap<String,Choice>(),
(r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));
If every new value for the same key name has to be overidden
then below will be the code :
public Map<String, Choice>
convertListToMap(List<Choice> choices) {
return choices.stream()
.collect(Collectors.toMap(Choice::getName,
Function.identity(),
(oldValue, newValue) -> newValue));
}
If all choices have to be grouped in a list for a name then
below will be the code:
public Map<String, Choice>
convertListToMap(List<Choice> choices) {
return choices.stream().collect(Collectors.groupingBy(Choice::getName));
}