2016-06-08 7 views
-2

Ich versuche, mehrere Sammlungen mithilfe von Streams und Lambdas in eine einzige Sammlung zu reduzieren. Allerdings muss ich angeben, wo ein doppelter Treffer aufgetreten ist.So kombinieren Sie mehrere Listen mit Streams und Lambas, die angeben, wo es ein Duplikat gibt

Grundsätzlich Ich habe folgende Situation:

Collection 1 von Kunden (Alle Personen)

Person 1 (Tom) 
Person 2 (Bob) 
Person 3 (Joe) 

Collection 2 von Prospects

Person 1 (Mike) 
Person 2 (Wilbur) 
Person 3 (Joe) 

Collection 3 Mitarbeiter

Person 1 (Mike) 
Person 2 (Tony) 
Person 3 (Sue) 
Person 4 (Joe) 

Ich mag diese Sammlung verwandeln ein neues Feld aufzunehmen, die mich mit der Karte tun können - wo bin ich verloren zu bekommen ist eigentlich, wie es zu glätten, so dass das Endergebnis so etwas wie diese

Sammlung wäre

Person 1 (Tom, "Customer") 
Person 2 (Bob, "Customer") 
Person 3 (Joe, "Customer, Prospect, Employee") 
Person 4 (Mike, "Prospect, Employee") 
Person 5 (Wilbur, "Prospect") 
Person 6 (Tony, "Employee") 
Person 7 (Sue, "Employee") 

Ich plane gerade, einen Zeichenkettenwert zu verursachen, um visuell darzustellen, zu welchen Bereichen sie gehören.

Thanks!

[EDIT]

Basierend auf dem Vorschlag unten, konnte ich die Lösung auf diese Weise testen ...

Klasse TestOutFlatMap { public void Test() {

Map<String, Collection<Person>> map = new HashMap<>(); 

    Collection<Person> p1 = new ArrayList<>(); 
    p1.add(new Person("Mike")); 
    p1.add(new Person("Joe")); 
    p1.add(new Person("Tony")); 

    Collection<Person> p2 = new ArrayList<>(); 
    p1.add(new Person("Wilbur")); 
    p1.add(new Person("Joe")); 
    p1.add(new Person("Molly")); 

    Collection<Person> p3 = new ArrayList<>(); 
    p1.add(new Person("Wilbur")); 
    p1.add(new Person("Joe")); 
    p1.add(new Person("Bubba")); 

    map.put("Customer", p1); 
    map.put("Prospect", p2); 
    map.put("Employee", p3); 

    Map<Person, String> output = map 
     .entrySet() 
     .stream() 
     .flatMap(t -> t.getValue().stream().map(g -> new Pair<>(t.getKey(), g))) 
     .collect(Collectors.toMap(t -> t.getValue(), u -> u.getKey(), (x, y) -> x + ", " + y)); 

    output.keySet().stream().forEach(p -> { 
     System.out.println(p); 
     System.out.println(output.get(p)); 
    }); 

} 
class Person { 
    String name; 

    Person(String name){ 
     this.name = name; 
    } 

    public String toString() {return this.name;} 

@Override 
public int hashCode() { 
    int hash = 5; 
    return hash; 
} 

@Override 
public boolean equals(Object obj) { 
    if (this == obj) { 
     return true; 
    } 
    if (obj == null) { 
     return false; 
    } 
    if (getClass() != obj.getClass()) { 
     return false; 
    } 
    final Person other = (Person) obj; 
    if (!Objects.equals(this.name, other.name)) { 
     return false; 
    } 
    return true; 
} 

}; 

} 

Allerdings waren meine Ergebnisse nicht wie erwartet. Sie kamen wie folgt zurück:

Bubba 
Customer 
Molly 
Customer 
Wilbur Customer, Customer 
Tony Customer 
Joe Customer, Customer, Customer 
Mike Customer 

Ich sehe nicht, wo es falsch verkettet ist.

Antwort

1

Sie könnten versuchen, Gruppierung, mit einem nachgeschalteten Kollektor die Gruppe in einen String, wie diese zu konvertieren:

 Map<Person, String> result = map 
     .entrySet() 
     .stream() 
     .flatMap(e -> e.getValue().stream().map(v -> new AbstractMap.SimpleEntry<>(v,e.getKey()))) 
     .collect(
      Collectors.groupingBy(Map.Entry::getKey,   // group Map.Entry by key 
       Collectors.mapping(Map.Entry::getValue,  // for each group, convert Map.Entry into the value 
        Collectors.joining(","))));    // convert the values into a comma-delimited String 

Wenn es irgendwie möglich ist, dass die gleichen Person zweimal unter dem gleichen Kategorie Schlüssel gefunden werden kann, und Sie möchten, dass einzigartige Kategorien für jede Person, man konnte jede Gruppe sammeln, um eine Set zu der Gruppe Elemente einzigartig zu machen, und dann wandeln die Set zu einem String mit Collectors.collectingAndThen wie folgt aus:

 Map<Person, String> result = map 
     .entrySet() 
     .stream() 
     .flatMap(e -> e.getValue().stream().map(v -> new AbstractMap.SimpleEntry<>(v,e.getKey()))) 
     .collect(Collectors.groupingBy(
       Map.Entry::getKey, 
       Collectors.mapping(Map.Entry::getValue, 
         Collectors.collectingAndThen(
           Collectors.toSet(), x -> String.join(",",x))))); 

Mit dem folgenden Setup,

 Map<String, Collection<Person>> map = new HashMap<>(); 
     Person person1 = new Person("Person1"); 
     Person person2 = new Person("Person2"); 
     map.put("Customer", Arrays.asList(person1, person2)); 
     map.put("Prospect", Arrays.asList(person1)); 
     map.put("Employee", Arrays.asList(person2, person2)); 

ich {Person1=Customer,Prospect, Person2=Employee,Customer}

+0

Danke für den Tipp - leider geben beide mir einen Kompilierfehler bei der Collect "Inferenzvariable K hat inkompatible Grenzen" und dieser "Der Typ Collect (Collector ) ist fehlerhaft" –

+0

Danke , @purringpigeon, ich hatte den falschen Typ für 'map'. Ich korrigierte meine Antwort –

+0

Das ist seltsam - Wenn ich das erste Beispiel ausführen, bekomme ich die gleichen Ergebnisse ... Der Sammler verkettet die gleiche Zeichenfolge wieder und wieder ... Joe "Kunde, Kunde, Kunde", anstatt was ich erwartet hatte Joe, "Kunde, Interessent, Angestellter". Im zweiten Beispiel wird die Zeichenfolge so verkleinert, dass nur "Kunde" angezeigt wird. –

1

Da Sie mehrere Sammlungen mit unterschiedlichen Typen haben, sollten Sie eine Kennung für jede Sammlung haben. So können Sie Ihre Eingabe am besten als Karte der Sammlung darstellen, wobei der Schlüssel der Karte den Sammlertyp darstellt, z. B. Kunde, Interessent und Mitarbeiter.

Jetzt, da Sie eine Map<String, Collection<Person>>, haben, müssen Sie nach jedem Element der Sammlungen gruppieren und zugeordneten Schlüssel verfolgen. Dazu müssen Sie Flatmap verwenden. folgenden Code sollte funktionieren:

Map<String, Collection<Person>> map = new HashMap<>(); 
    map.put("Customer", ...); 
    map.put("Prospect", ...; 
    map.put("Employee", ...; 

    Map<Person, String> output = map 
     .entrySet() 
     .stream() 
     .flatMap(t -> t.getValue().stream().map(g -> new Pair<>(t.getKey(), g))) 
     .collect(Collectors.toMap(
       t -> t.getValue(), u -> u.getKey(), (x, y) -> x + ", " + y)); 

Bitte beachten Sie die Klasse Pair aus javafx.util.Pair verwendet wird.

+0

Eigentlich hat das nicht funktioniert. Es hat fast funktioniert. Ich habe beispielsweise folgendes Ergebnis: Joe, "Kunde, Kunde, Kunde". Ich habe die richtigen Werte in der Karte für die Schlüssel erhalten. –

+0

Nun, Ihr Code ist falsch. Sie erstellen 3 Sammlungen, p1, p2, p3. Aber immer Elemente in p1 hinzufügen. Versuchen Sie es zu korrigieren, und Sie erhalten die richtige Ausgabe. – mks

+0

Yup - Ich sah, dass auf dem anderen Post - diese Frage den ganzen Tag verfolgt. Vielen Dank. –

Verwandte Themen