Java不使用Stream实现单词词频从高到低排序输出
Java 不使用Stream API实现词频降序打印
问题原因
HashMap属于无序存储结构,直接遍历entrySet()得到的顺序是键哈希值映射到桶的排列顺序,代码中未加入词频排序逻辑,因此输出顺序不符合预期。
调整方案
原有词频统计逻辑不需要改动,只需要在遍历输出前对键值对集合做自定义排序即可,全程无需使用Stream API,步骤如下:
- 将Map的所有Entry存入支持自定义排序的
ArrayList - 调用
Collections.sort()方法实现排序规则:优先按词频(Entry的value值)降序排列,若存在词频相同的单词,追加按单词字典序升序的规则保证输出结果稳定 - 遍历排序完成的List拼接输出结果
调整后完整代码
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.*; import java.util.Map.Entry; public class InputOutput { private String wordsFrequency() { StringBuilder result = new StringBuilder(); // 自动关闭IO资源,避免资源泄漏 try (BufferedReader reader = new BufferedReader(new FileReader("words.txt"))) { Map<String, Integer> map = new HashMap<>(); String line; while ((line = reader.readLine()) != null) { Scanner scan = new Scanner(line); while (scan.hasNext()) { String word = scan.next(); if (map.containsKey(word)) { map.put(word, map.get(word) + 1); } else { map.put(word, 1); } } scan.close(); } // 转换为List做自定义排序 List<Entry<String, Integer>> entryList = new ArrayList<>(map.entrySet()); // 定义排序规则 Collections.sort(entryList, new Comparator<Entry<String, Integer>>() { @Override public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) { int freqCompare = o2.getValue().compareTo(o1.getValue()); if (freqCompare != 0) { return freqCompare; } // 词频相同按单词字典序升序 return o1.getKey().compareTo(o2.getKey()); } }); // 拼接排序后的结果 for (Entry<String, Integer> entry : entryList) { result.append(entry.getKey()).append("\t").append(entry.getValue()).append("\n"); } } catch (IOException e) { e.printStackTrace(); } return result.toString(); } public static void main(String[] args) { InputOutput requestedData = new InputOutput(); System.out.println(requestedData.wordsFrequency()); } }
运行验证
针对提供的words.txt测试文件,运行后输出完全符合预期:
is 7 the 4 sunny 2 day 1
注:不建议通过自定义
TreeMap实现该需求,TreeMap默认基于键排序,强行绑定值排序会出现词频相同的单词被判定为重复键、统计结果被覆盖的问题,稳定性远低于List排序方案。
内容的提问来源于stack exchange,提问作者Orest Dymarchuk
相关产品推荐
相关产品推荐

