2016-07-20 8 views
4

Ich habe Karte mit Schlüssel als String und Wert als Liste. Liste kann 10 eindeutige Werte haben. Ich muss diese Karte mit Schlüssel als Ganzzahl und Wert als Liste konvertieren. Beispiel wie folgt:Java8 Streams: Karte mit Werten als Liste transponieren

Input:

"Key-1": 1,2,3,4

"Key-2": 2,3,4,5

"Key-3": 3,4,5,1

Erwartete Ausgabe:

1: "Key-1", "Key-3"

2: "Key-1", "Key-2"

3: "Key-1", "Key-2", "Key-3"

4: "Key-1" "Key-2", "Key-3"

5: "Key-2", "Key-3"

ich bin mir bewusst, dass für Loops i dies erreichen kann, aber ich brauchte Dose wissen Dies kann über streams/lamda in java8 geschehen.

-Danke.

Antwort

2

Es ist ein bisschen beängstigend (Ich versuche es im Allgemeinen zu brechen sie besser lesbar zu machen), aber man könnte es auf diese Weise tun:

Map<Integer, List<String>> transposeMap = new HashMap<>(); 

map.forEach((key, list) -> list.stream().forEach(
    elm -> transposeMap.put(elm, 
     transposeMap.get(elm) == null ? Arrays.asList(key) : (Stream.concat(transposeMap.get(elm).stream(), 
      Arrays.asList(key).stream()).collect(Collectors.toList()))))); 

Map<String, List<Integer>> map Angenommen, Ihre ursprüngliche Karte, die Sie umsetzen wollen. transposeMap wird die Karte übertragen haben, die Sie benötigen.

+1

Streams sind besser geeignet für Staatenlose Operationen.Während diese Antwort richtig ist, wäre sie besser für einen imperativen Stil geeignet. Es ist im Grunde die Loop-Strategie des OP, aber stattdessen mit einem 'forEach' umbenannt. – 4castle

+1

'forEach' gehört nicht zu' streams'. Es wird in "Iterable", "list.stream()" deklariert. ForEach sollte "list.forEach" sein. –

+1

@ Jean-François Savard: Streams haben auch eine 'forEach'-Methode, allerdings mit einer etwas anderen Semantik. – Holger

11

könnte eine Idee sein, alle Wert-Schlüsselpaare von der ursprünglichen Karte zu erzeugen und dann die Gruppe der Schlüssel durch diese Werte:

import java.util.AbstractMap.SimpleEntry; 

import static java.util.stream.Collectors.groupingBy; 
import static java.util.stream.Collectors.mapping; 
import static java.util.stream.Collectors.toList; 

... 

Map<Integer, List<String>> transposeMap = 
    map.entrySet() 
     .stream() 
     .flatMap(e -> e.getValue().stream().map(i -> new SimpleEntry<>(i, e.getKey()))) 
     .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList()))); 
4

Alexis’ answer die allgemeine Lösung für diese Art von Aufgabe enthält, flatMap und ein mit temporärer Halter für die Kombination aus Schlüssel und abgeflachtem Wert. Die einzige Alternative, die Erstellung der temporären Halter Objekte zu vermeiden, ist die Logik des groupingBy Kollektor neu zu implementieren und Einsetzen des Schleife über die Werteliste Logik in den Akkumulator-Funktion:

Map<Integer, List<String>> mapT = map.entrySet().stream().collect(
    HashMap::new, 
    (m,e) -> e.getValue().forEach(
       i -> m.computeIfAbsent(i,x -> new ArrayList<>()).add(e.getKey())), 
    (m1,m2) -> m2.forEach((k,v) -> m1.merge(k, v, (l1,l2)->{l1.addAll(l2); return l1;}))); 
1

Sie in erreichen können Auf diese Weise

Angenommen, ich habe Person Klasse mit Geschlecht und Alter. Ich will es in dieser Form habe ich einfach

Map<SEX,List<Person>> map = personList.stream() 

          .collect(Collectors.groupingBy(Person::getGender)); 

es mir bekommt etwas wie unten schreiben würde

Map<SEX,List<Person>> 

bekommen (ein Schlüssel gegen mehrere Werte)

key:MALE 
age31sexMALE 
age28sexMALE 

key:FEMALE 
age40sexFEMALE 
age44sexFEMALE 
Verwandte Themen