英文:
Count occurrences in string and output sorted result by ocuurence_count desc, name
问题
Here's a more concise solution using Java Stream API to achieve the same result:
String str = "Charlie Jennifer Charlie Bob Charlie Charlie Bob Jennifer Alice Alice";
Arrays.stream(str.split(" "))
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue()
.reversed()
.thenComparing(Map.Entry.comparingByKey()))
.forEach(System.out::println);
This solution follows the same logic as your original code but uses Collectors.groupingBy
and Collectors.counting()
directly within the collect
method, which makes the code more concise.
英文:
Given a string:
String str = "Charlie Jennifer Charlie Bob Charlie Charlie Bob Jennifer Alice Alice";
Need to count name occurrences in the given string and output sorted result by occurrence count (desc), then by name.
Here is my solution:
Arrays.stream(str.split(" "))
.collect(groupingBy(identity(), counting())).entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue()
.reversed()
.thenComparing(Map.Entry.comparingByKey()))
.forEach(System.out::println);
My question is: do you know more elegant solution using Java Stream API ?
答案1
得分: 2
按照评论中所述,这里实际上没有太多可以改进的地方。
可能的改进是,你可以将结果收集到TreeMap
中,并使用 lambda 表达式按值进行比较,而无需调用 reversed()
:
Arrays.stream(str.split(" "))
.collect(groupingBy(w -> w, TreeMap::new, counting()))
.entrySet().stream()
.sorted((a, b) -> b.getValue().compareTo(a.getValue()))
.forEach(System.out::println);
类似地,可以使用 toMap
收集器替代 groupingBy
和 counting
:
Arrays.stream(str.split(" "))
.collect(toMap(w -> w, x -> 1, Long::sum, TreeMap::new))
.entrySet().stream()
.sorted((a, b) -> b.getValue().compareTo(a.getValue()))
.forEach(System.out::println);
英文:
As mentioned in the comments, there's not really much to improve here.
Possibly, you could collect the results into a TreeMap
and use lambda to compare by values without calling reversed()
:
Arrays.stream(str.split(" "))
.collect(groupingBy(w -> w, TreeMap::new, counting()))
.entrySet().stream()
.sorted((a, b) -> b.getValue().compareTo(a.getValue()))
.forEach(System.out::println);
Similarly, toMap
collector could be used instead of groupingBy
and counting
:
Arrays.stream(str.split(" "))
.collect(toMap(w -> w, x -> 1, Long::sum, TreeMap::new))
.entrySet().stream()
.sorted((a, b) -> b.getValue().compareTo(a.getValue()))
.forEach(System.out::println);
答案2
得分: 1
可能不使用流会稍微不那么冗长,但是仍然需要先进行分组,然后再进行排序:
Map<String, Long> map = new HashMap<>();
for (String s : str.split(" ")) map.merge(s, 1L, Long::sum);
在这里,我使用了 Map.merge
方法按频率对单词进行分组。现在我们需要从条目中创建一个列表,然后进行排序:
List<Map.Entry<String, Long>> list = new ArrayList<>(map.entrySet());
list.sort(Map.Entry.comparingByValue()
.reversed()
.thenComparing(Map.Entry.comparingByKey()));
现在我们有一个按照您的要求排序的 Map.Entry
列表。
如果您需要从这些条目创建一个映射,它应该是一个 LinkedHashMap
,以保留插入顺序:
Map<String, Long> sortedByValue = new LinkedHashMap<>();
list.forEach(e -> sortedByValue.put(e.getKey(), e.getValue()));
英文:
Maybe not using streams is a little bit less verbose but, still, you need to group first and then sort:
Map<String, Long> map = new HashMap<>();
for (String s : str.split(" ")) map.merge(s, 1L, Long::sum);
Here I'm using the Map.merge
method to group words by frequency. Now we need to create a list from the entries and sort it:
List<Map.Entry<String, Long>> list = new ArrayList<>(map.entrySet());
list.sort(Map.Entry.comparingByValue()
.reversed()
.thenComparing(Map.Entry.comparingByKey()));
And now we have a list of Map.Entry
in list
, sorted as per your requirements.
If you need to create a map from these entries, it should be a LinkedHashMap
, to preserve insertion order:
Map<String, Long> sortedByValue = new LinkedHashMap<>();
list.forEach(e -> sortedByValue.put(e.getKey(), e.getValue()));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论