2016-07-28 1 views
1

J'ai une liste d'objets Liste listOfStudents: Objet:Recherche max occurance d'une chaîne - Tie cas

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

J'essaie de la trouver le nom de l'étudiant qui se produit le plus grand nombre de fois et faire que j'ai utilisé:

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

S'il n'y a pas de lien alors j'utilise

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

pour déterminer le nom qui a eu lieu le plus de fois.

mais il peut arriver qu'il y ait une égalité au nom des étudiants et dans ce cas je veux choisir le nom de l'étudiant qui est venu à l'école le plus de fois, ie le nom de l'étudiant qui a la somme la plus élevée de numberOfTimesComeToSchool sur tous les noms.

Par exemple:

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 

Dans ce cas, la réponse correcte serait Bonjour comme la somme des numberOfTimesComeToSchool est 5 alors que pour le reste des noms son seul 4, même si tous les noms se produisent le même nombre de temps.

Toute aide à ce sujet serait appréciée.

+0

Comment pourrais-je utiliser cela? Je ne connais jamais les noms des élèves avant la main. – Massa

+0

Appelez 'HashBag.uniqueSet()' et passez en revue dessus. Docs: https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/bag/HashBag.html – ifly6

Répondre

3

Le problème en utilisant .map(Student::getName), c'est que vous perdez l'information sur le nombre de fois que chaque élève arrive à l'école.

Au lieu de cela, il suffit d'utiliser groupingBy sur la liste d'origine afin que vous obteniez un Map<String, List<Student>>. Passez ensuite en revue l'ensemble d'entrées de la carte et trouvez l'entrée max en comparant d'abord la taille de la liste, puis la somme de numberOfTimesComeToSchool en cas d'égalité.

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); 

L'inférence de type est pas encore assez puissant, vous devez spécifier les paramètres de type dans le comparateur, ce qui le rend assez difficile à lire.

Enfin, vous pouvez faire une seule ligne en utilisant Collectors.collectingAndThen:

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)));