2016-07-28 4 views
1

ich eine Liste von Objekten Liste listOfStudents haben: Objekt:Suche nach max Vorkommen eines Strings - Tie Fall

private class Students 
{ 
    private String name; 
    private int numberOfTimesComeToSchool; 
} 

Ich versuche, die den Namen des Studenten finden, die die meiste Anzahl von Malen auftritt und tun, dass ich verwendet:

listOfStudents.stream().map(Student::getName)collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); 

Wenn es keine Krawatte dann verwende ich

Collections.max(collect.entrySet(), Map.Entry.comparingByValue()).getKey(); 

zu bestimmen der Name, der am häufigsten aufgetreten ist.

aber dann kann es vorkommen, dass es einen Unentschieden im Namen der Schüler gibt und in diesem Fall möchte ich den Namen des Schülers wählen, der die meiste Zeit in die Schule gekommen ist, dh der Name des Schülers die höchste Summe von numberOfTimesComeToSchool aus allen Namen.

Zum Beispiel:

Student 1: Name: Hello numberOfTimesComeToSchool: 1 
Student 2: Name: Hello numberOfTimesComeToSchool: 4 
Student 3: Name: Trial numberOfTimesComeToSchool: 2 
Student 4: Name: Trial numberOfTimesComeToSchool: 2 
Student 5: Name: NeedThis numberOfTimesComeToSchool: 2 
Student 6: Name: NeedThis numberOfTimesComeToSchool: 2 

In diesem Fall richtige Antwort Hallo als die Summe der numberOfTimesComeToSchool wäre, ist 5, während für den Rest des Namen seiner nur 4, obwohl alle Namen die gleiche Anzahl auftreten von Zeiten.

Jede Hilfe mit diesem würde geschätzt werden.

+0

Wie würde ich in der Lage sein, das zu benutzen? Ich kenne die Namen der Schüler nie vorher. – Massa

+0

Rufen Sie 'HashBag.uniqueSet()' auf und iterieren Sie darüber. Dokumente: https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/bag/HashBag.html – ifly6

Antwort

3

Das Problem mit .map(Student::getName) ist, dass Sie die Informationen darüber verlieren, wie oft jeder Schüler zur Schule kommt.

Verwenden Sie stattdessen groupingBy auf der ursprünglichen Liste, so dass Sie eine Map<String, List<Student>> zurückgeben. Dann iteriere über den Eintragssatz der Karte und finde den maximalen Eintrag, indem du zuerst die Größe der Liste und dann die Summe von numberOfTimesComeToSchool im Falle eines Unentschiedens vergleichst.

Map<String, List<Student>> map = 
     listOfStudents.stream().collect(Collectors.groupingBy(Student::getName)); 

Optional<String> studentName = 
     map.entrySet() 
      .stream() 
      .max(Comparator.<Map.Entry<String, List<Student>>>comparingInt(e -> e.getValue().size()) 
          .thenComparingInt(e -> e.getValue().stream().mapToInt(Student::getNumberOfTimesComeToSchool).sum())) 
      .map(Map.Entry::getKey); 

Die Typinferenz ist noch nicht stark genug, so dass Sie die Typparameter in der Hand geben haben, die es recht schwer zu lesen macht.

Schließlich können Sie es ein Einzeiler von Collectors.collectingAndThen mit:

Optional<String> studentName = 
    listOfStudents.stream() 
        .collect(collectingAndThen(groupingBy(Student::getName), 
                 m -> m.entrySet() 
                   .stream() 
                   .max(Comparator.<Map.Entry<String, List<Student>>>comparingInt(e -> e.getValue().size()) 
                      .thenComparingInt(e -> e.getValue().stream().mapToInt(Student::getNumberOfTimesComeToSchool).sum())) 
                   .map(Map.Entry::getKey))); 
Verwandte Themen