Java 8 - 统计字数,然后按降序排列
Java 8 - Count of words and then arrange in desc order
我有一个单词列表,说
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()));
我是一个简单的人,所以我会先用一个Map<String, Integer>
来计算每个单词。
然后为每个计数创建一个 TreeSet
,并将它们存储在 TreeMap<Integer, TreeSet>
中。从那里应该相当简单。
最难的部分是排序。由于您只想保留结果中的前 7 个元素,并且希望按其值对 Map 进行排序,因此我们需要创建一个包含所有结果的 Map,对其进行排序,然后保留 7 个结果。
在下面的代码中,每个单词都是小写的,并且自己分组,统计出现的次数。然后,我们需要对这个映射进行排序,以便我们在条目上创建一个 Stream,根据值(降序)然后根据键对它们进行排序。保留前 7 个元素,映射到它们的键(对应于单词)并收集到一个 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]
请注意,您在想要的输出中犯了一个错误:"are"
实际上像 "you"
一样出现了 3 次,所以它应该在 [=16= 之前]
注意:这段代码假定了很多静态导入,即:
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
虽然@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
有时候解决一个问题最好的不是算法,而是数据结构。我想你在这里需要的是一个包。由于您希望输出按出现次数排序,然后按键排序,因此您应该使用的特定数据结构是 TreeBag
。以下代码将使用 Eclipse Collections 和 Java 8 个流:
String string =
"Hello alan i am here where are you and what are you doing hello are you there";
List<ObjectIntPair<String>> pairs =
Stream.of(string.toLowerCase().split(" "))
.collect(Collectors.toCollection(TreeBag::new))
.topOccurrences(7);
System.out.println(pairs);
此代码将输出:
// Strings with occurrences
[are:3, you:3, hello:2, alan:1, am:1, and:1, doing:1, here:1, i:1, there:1, what:1, where:1]
topOccurrences()
方法具有处理平局的逻辑,这基本上让开发人员决定他们希望如何处理平局的情况。如果您恰好想要此列表中的前七个项目,则可以将调用链接到 .take(7);
代码还可以进一步简化为:
List<ObjectIntPair<String>> pairs =
TreeBag.newBagWith(string.split(" ")).topOccurrences(7);
System.out.println(pairs);
静态工厂方法 TreeBag.newBagWith()
接受可变参数,因此您可以将 String.split()
的结果直接传递给它。
注意:我是 Eclipse Collections 的提交者。
两步解决方案:group/count,然后按计数降序处理
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
我有一个单词列表,说
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()));
我是一个简单的人,所以我会先用一个Map<String, Integer>
来计算每个单词。
然后为每个计数创建一个 TreeSet
,并将它们存储在 TreeMap<Integer, TreeSet>
中。从那里应该相当简单。
最难的部分是排序。由于您只想保留结果中的前 7 个元素,并且希望按其值对 Map 进行排序,因此我们需要创建一个包含所有结果的 Map,对其进行排序,然后保留 7 个结果。
在下面的代码中,每个单词都是小写的,并且自己分组,统计出现的次数。然后,我们需要对这个映射进行排序,以便我们在条目上创建一个 Stream,根据值(降序)然后根据键对它们进行排序。保留前 7 个元素,映射到它们的键(对应于单词)并收集到一个 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]
请注意,您在想要的输出中犯了一个错误:"are"
实际上像 "you"
一样出现了 3 次,所以它应该在 [=16= 之前]
注意:这段代码假定了很多静态导入,即:
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
虽然@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
有时候解决一个问题最好的不是算法,而是数据结构。我想你在这里需要的是一个包。由于您希望输出按出现次数排序,然后按键排序,因此您应该使用的特定数据结构是 TreeBag
。以下代码将使用 Eclipse Collections 和 Java 8 个流:
String string =
"Hello alan i am here where are you and what are you doing hello are you there";
List<ObjectIntPair<String>> pairs =
Stream.of(string.toLowerCase().split(" "))
.collect(Collectors.toCollection(TreeBag::new))
.topOccurrences(7);
System.out.println(pairs);
此代码将输出:
// Strings with occurrences
[are:3, you:3, hello:2, alan:1, am:1, and:1, doing:1, here:1, i:1, there:1, what:1, where:1]
topOccurrences()
方法具有处理平局的逻辑,这基本上让开发人员决定他们希望如何处理平局的情况。如果您恰好想要此列表中的前七个项目,则可以将调用链接到 .take(7);
代码还可以进一步简化为:
List<ObjectIntPair<String>> pairs =
TreeBag.newBagWith(string.split(" ")).topOccurrences(7);
System.out.println(pairs);
静态工厂方法 TreeBag.newBagWith()
接受可变参数,因此您可以将 String.split()
的结果直接传递给它。
注意:我是 Eclipse Collections 的提交者。
两步解决方案:group/count,然后按计数降序处理
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