Java 8 - 单词计数然后以desc顺序排列

时间:2015-11-22 13:37:03

标签: java java-8 java-stream collectors

我有一个单词列表,比如说

List<String> words = Arrays.asList("Hello alan i am here where are you"+  
  "and what are you doing hello are you there");

如何按降序排列列表中重复多次的前七个单词?然后单个输入词应按字母顺序排列。所以上面的输出应该是前七个单词

you (3)
are (2)
hello (2)
alan (1)
am (1)
and (1)
doing (1)

我希望在Java 8中使用流,lamda。

我正在尝试这种方式。 首先对列表进行排序 其次,在单词列表中获取单词的映射。

List<String> sortedWords = Arrays.asList("Hello alan i am here where are you and what are you doing hello you there".split(" "))
            .stream().sorted().collect(toList());

Map<String, Long> collect = 
            sortedWords.stream().collect(groupingBy(Function.identity(), counting()));

4 个答案:

答案 0 :(得分:9)

最困难的部分是分拣。由于您只想保留结果中的7个第一个元素,并且您希望按照其值对Map进行排序,我们需要创建所有结果的Map,对其进行排序,然后保留7个结果。

在下面的代码中,每个单词都是低位的,并按自己分组,计算出现的次数。然后,我们需要对这个映射进行排序,以便我们在条目上创建一个Stream,根据值(按降序排序)然后根据键对它们进行排序。保留7个第一个元素,映射到它们的键(对应于单词)并收集到-webkit-text-fill-color中,从而保持相遇顺序。

List

输出:

public static void main(String[] args) {
    String sentence = "Hello alan i am here where are you and what are you doing hello are you there";
    List<String> words = Arrays.asList(sentence.split(" "));

    List<String> result = 
            words.stream()
                 .map(String::toLowerCase)
                 .collect(groupingBy(identity(), counting()))
                 .entrySet().stream()
                 .sorted(Map.Entry.<String, Long> comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey()))
                 .limit(7)
                 .map(Map.Entry::getKey)
                 .collect(toList());

    System.out.println(result);
}

请注意,您在想要的输出中犯了一个错误:[are, you, hello, alan, am, and, doing] 实际上出现了3次,如"are"所以它应该在之前

注意:此代码假定有很多静态导入,即:

"you"

答案 1 :(得分:4)

虽然@Tunaki解决方案很棒,但使用my StreamEx library很有意思,它可以解决单流管道中的问题(直到单终端操作才会执行实际操作被称为):

Map<String, Long> map = StreamEx.of(words)
    .map(String::toLowerCase)
    .sorted() // sort original words, so now repeating words are next to each other
    .runLengths() // StreamEx feature: squash repeating words into Entry<String, Long>
    .sorted(Entry.<String, Long> comparingByValue().reversed()
                 .thenComparing(Entry.comparingByKey()))
    .limit(7) // Sort and limit
    .toCustomMap(LinkedHashMap::new); // Single terminal operation: store to LinkedHashMap

或者只需要单词:

List<String> list =StreamEx.of(words)
    .map(String::toLowerCase)
    .sorted() // sort original words, so now repeating words are next to each other
    .runLengths() // StreamEx feature: squash repeating words into Entry<String, Long>
    .sorted(Entry.<String, Long> comparingByValue().reversed()
                 .thenComparing(Entry.comparingByKey()))
    .limit(7) // Sort and limit
    .keys() // Drop counts leaving only words
    .toList(); // Single terminal operation: store to List

答案 2 :(得分:1)

我是一个简单的人,所以我先使用time来计算每个单词。 然后为每个计数创建Map<String, Integer>,并将其存储在TreeSet中。从那里应该相当直截了当。

答案 3 :(得分:0)

两步解决方案:组/计数,然后按计数降序处理

List<String> words = Arrays.asList("Hello alan i am here where are you and what are you doing hello you there".split(" "));

Map<String, Long> collect = words.stream()
        .map(String::toLowerCase) // convert to lower case
        .collect( // group and count by name
                Collectors.groupingBy(Function.identity(), Collectors.counting()));

collect.keySet().stream()
        .sorted( // order by count descending, then by name
                Comparator
                        .comparing(collect::get)
                        .reversed()
                        .thenComparing(Collator.getInstance()))
        .map(k -> k + " (" + collect.get(k) + ")") // map to name and count string
        .limit(7) // only first 7 entries
        .forEach(System.out::println); // output