2016-04-29 9 views
2

Ich versuche, einen eleganten Weg zu finden, um eine Karte zu erstellen, die Gruppe von Feldwerten von Feldnamen mit Hilfe von Java 8 als die folgenden:Java 8: Gruppieren Feldwerte von Feldnamen

@Test 
public void groupFieldValuesByFieldNames() { 
    Person lawrence = aPerson().withFirstName("Lawrence").withLastName("Warren").born(); 
    Person gracie = aPerson().withFirstName("Gracie").withLastName("Ness").born(); 

    Map<String, List<String>> valuesByFieldNames = new HashMap<>(); 
    Stream.of(lawrence, gracie).forEach(person -> { 
     valuesByFieldNames.computeIfAbsent("lastName", s -> new ArrayList<>()).add(person.getLastName()); 
     valuesByFieldNames.computeIfAbsent("firstName", s -> new ArrayList<>()).add(person.getFirstName()); 
    }); 

    assertThat(valuesByFieldNames, hasEntry("lastName", asList("Warren", "Ness"))); 
    assertThat(valuesByFieldNames, hasEntry("firstName", asList("Lawrence", "Gracie"))); 
} 
+1

Wenn Sie verpflichtet fühlen, etwas zu tun, würde ich mit 'Map >' beginnen, die jedes Feldnamen zugeordnet ein Getter für dieses Feld. –

Antwort

2

Versuchen Sie es.

Map<String, List<String>> valuesByFieldNames = Stream.of(lawrence, gracie) 
    .flatMap(p -> Stream.of(new String[]{"firstName", p.getFirstName()}, 
          new String[]{"lastName", p.getLastName()})) 
    .collect(Collectors.groupingBy(a -> a[0], 
      Collectors.mapping(a -> a[1], Collectors.toList()))); 

Oder allgemeiner

Map<String, List<String>> valuesByFieldNames = Stream.of(lawrence, gracie) 
    .flatMap(p -> Stream.of(new AbstractMap.SimpleEntry<>("firstName", p.getFirstName()), 
          new AbstractMap.SimpleEntry<>("lastName", p.getLastName()))) 
    .collect(Collectors.groupingBy(e -> e.getKey(), 
      Collectors.mapping(e -> e.getValue(), Collectors.toList()))); 
2

Sie haben können die folgenden, die korrekt parallel arbeiten:

Map<String, List<String>> valuesByFieldNames = 
    Stream.of(lawrence, gracie).collect(HashMap::new, (m, p) -> { 
     m.computeIfAbsent("lastName", s -> new ArrayList<>()).add(p.getLastName()); 
     m.computeIfAbsent("firstName", s -> new ArrayList<>()).add(p.getFirstName()); 
    }, (m1, m2) -> m2.forEach((k, v) -> m1.merge(k, v, (l1, l2) -> { l1.addAll(l2); return l1; }))); 

Was dies bedeutet ist, dass es jede Person in eine mutable HashMap zu sammeln. Der Akkumulator berechnet den Nachnamen und den Vornamen, indem er computeIfAbsent aufruft, genau wie Ihr ursprünglicher Code. Der Kombinierer führt zwei Karten zusammen, indem er über die Einträge der zweiten Karte iteriert und jeden Schlüssel in die erste Karte einfügt; Im Konfliktfall ist der Wert die Addition der beiden Listen.