Считать вхождения строки в списке, а затем отсортировать результат - Java 8 - PullRequest
0 голосов
/ 10 января 2019

Я вижу, что есть много разновидностей этого типа вопросов "подсчет и сортировка" (ближайший связанный вопрос был этот ), но ни один из них не работает в моей ситуации.

Это мой код.

List<Employee> employees = new ArrayList<>();

Employee e1 = new Employee;
e1.setFirstName("Beth");

Employee e2 = new Employee;
e1.setFirstName("Beth");

Employee e3 = new Employee;
e1.setFirstName("Andrew");

// similarly I'm creating millions of employees and adding them to my list below 

employees.add(e1);
employees.add(e2);
employees.add(e3);
employees.add(e53456667);

//count occurrences of first names
Map<String, Long> employeeFirstNameCount = employees.stream()
                .collect(Collectors.groupingBy(p -> p.getFirstName(), Collectors.counting()));

В результате

{Beth=2, Andrew=34674, Charles=2388491, John=223545, Alex=2345562}

Но мне нужно это как

{Alex=2345562, Andrew=34674, Beth=2, Charles=2388491, John=223545}

Я пробовал это (ссылка ):

Map<String, Long> employeeFirstNameCount = employees.stream()
        .collect(Collectors.groupingBy(p -> p.getFirstName(), Collectors.counting()))
        .entrySet().stream()
        .sorted(Map.Entry.<String, Long> comparingByValue(Comparator.naturalOrder()).thenComparing(Map.Entry.comparingByKey()))
        .limit(20)
        .map(Map.Entry::getKey)
        .collect(toList());

Но получаю эту ошибку

enter image description here

Теперь я не в курсе. Может кто-нибудь, пожалуйста, помогите?

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Вы можете получить желаемый результат, если вы используете TreeMap вместо значения по умолчанию HashMap, когда создаете Map следующим образом:

Map<String, Long> employeeFirstNameCount = employees.stream()
            .collect(Collectors.groupingBy(Employee::getFirstName,
                                           TreeMap::new,
                                           Collectors.counting()));

java.util.TreeMap использует естественный порядок своих ключей (этого достаточно для того, что вам нужно), или вы можете предоставить пользовательский Comparator

Примечание. Я использую лямбда-выражение Employee::getFirstName вместо p -> p.getFirstName(), но оба результата дают одинаковый результат.

0 голосов
/ 10 января 2019

Поскольку вы хотите получить результат как Map<String, Long>, вы не должны отображаться на ключ ввода, т. Е. .map(Map.Entry::getKey), поскольку мы также не должны собирать данные в список, т. Е. .collect(toList()), поскольку в конечном итоге вы в конечном итоге получите с List<String> вместо Map<String, Long>, скорее после сортировки по указанным критериям, вы должны собрать на карту и, в частности, LinkedHashMap:

Map<String, Long> result = employees.stream()
                .collect(Collectors.groupingBy(p -> p.getFirstName(), 
                           Collectors.counting()))
                .entrySet().stream()
                .sorted(Map.Entry.<String, Long> comparingByKey())
                .limit(20)
                .collect(Collectors.toMap(Map.Entry::getKey, 
                    Map.Entry::getValue, 
                    (l,r) -> l, 
                    LinkedHashMap::new));

Компаратор, приведенный выше, будет сортировать только по ключам, поскольку это то, что, по-видимому, и предполагает ваш ожидаемый результат.


Обратите внимание, что если вам не нужна операция limit после группировки, ее можно упростить до:

employees.stream()
         .sorted(Comparator.comparing(Employee::getFirstName))
         .collect(Collectors.groupingBy(Employee::getFirstName,
                        LinkedHashMap::new,
                        Collectors.counting()));
...