繁体   English   中英

在 Java 中打印从 Max 到 Min 的单词出现次数(无流)

[英]Print words occurrences from Max to Min in Java (No Streams)

您能否就如何将单词出现从最频繁的值打印到最不频繁的值给我建议?

我尝试了不同的方法,所以我停在地图上,它给了我更接近的结果。

public class InputOutput {

    private String wordsFrequency() {
        StringBuilder result = new StringBuilder();

        try {
            Map<String, Integer> map = new HashMap<>();
            BufferedReader reader = new BufferedReader(new FileReader("words.txt"));
            String words;

            while ((words = reader.readLine()) != null) {
                Scanner scan = new Scanner(words);
                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();
            }
            reader.close();
            Set<Entry<String, Integer>> entrySet = map.entrySet();

            for (Entry<String, Integer> entry : entrySet) {
                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());

    }
}

文件内容:

the day is sunny the the
the sunny is is is is is is

预期输出:

is  7
the 4
sunny   2
day 1

我得到的输出:

the 4
is  7
sunny   2
day 1
List<Map.Entry<String, Integer>> frequencies = new ArrayList<>(map.entrySet());
frequencies.sort(Comparator.comparing(e -> e.getValue()).reversed());

可以对 List 进行排序,也可以使用 Comparator 对 TreeSet 进行排序(SortedSet)。 这里有一个返回 Comparable 值的函数。

我敢肯定有一种更清洁的方法可以做到这一点,但不使用流,这就是我想出的:

String src = "the day is sunny the the the sunny is is is is is is";

try (Scanner scanner = new Scanner(new StringReader(src))) {
    Map<String, Integer> map = new HashMap<>();
    while (scanner.hasNext()) {
        String word = scanner.next();
        map.merge(word, 1, (a, b) -> a + 1);
    }
    Map<Integer, Collection<String>> cntMap = new TreeMap<>(Comparators.reverseOrder());
        
    for (Entry<String, Integer> entry : map.entrySet()) {
       Collection<String> list = cntMap.get(entry.getValue());
       if (list == null) {
           list = new TreeSet<>();
           cntMap.put(entry.getValue(), list);
       }
       list.add(entry.getKey());
    }

    for (Entry<Integer, Collection<String>> entry : cntMap.entrySet()) {
       System.out.println(entry.getValue() + " : " + entry.getKey());
    }
}

您提供的代码的问题:

  • 如果出现异常,则不会关闭流。 更重要的是,如果所有数据都可以从文件中成功读取,但在关闭阅读器期间发生异常,您将获得数据,因为负责处理地图的代码行将不会被执行。 对资源使用 try以确保您的资源将正确关闭。

  • 不要在一种方法中塞进太多逻辑。 正如单一职责原则所建议的那样,至少有两个职责,它们应该存在于不同的方法中。

  • 您可以拆分从文件中读取的行,而不是使用Scanner

  • 而且您当前的逻辑很幸运排序。 这就是您当前和预期的输出不匹配的原因。

您可以生成一个地图Map<String, Integer>表示每个单词的频率。

然后创建此地图的条目列表,根据值按降序对其进行排序。

最后将排序的条目列表转换为可以打印的字符串列表

private static Map<String, Integer> wordsFrequency(String file) {
    
    Map<String, Integer> frequencies = new HashMap<>();
    
    try (var reader = Files.newBufferedReader(Path.of(file))) {
        String[] words = reader.readLine().split(" ");
        for (String word : words) {
        //  frequencies.merge(word, 1, Integer::sum); // an equivalent of the 2 lines below
            int count = frequencies.getOrDefault(word, 0);
            frequencies.put(word, count + 1);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    return frequencies;
}

public static List<String> mapToSortedList(Map<String, Integer> map) {
    List<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
    // sorting the list of entries
    entries.sort(Map.Entry.<String, Integer>comparingByValue().reversed());
    
    List<String> result = new ArrayList<>();
    for (Map.Entry<String, Integer> entry :entries) {
        result.add(entry.getKey() + " " + entry.getValue());
    }
    return result;
}

public static void main(String[] args) {
    mapToSortedList(wordsFrequency("filePath.txt")).forEach(System.out::println);
}

您已经有了数据,这里是如何以反向排序的顺序获取它们。

  • 使用比较器声明一个SortedSet来比较条目的值
  • 然后将条目添加到SortedSet中,它们将在输入时进行排序。
  • Entry.comparingByValue(Comparator.reversed())用于仅按计数和倒序排序。
SortedSet<Entry<String,Integer>> set
            = new TreeSet(Entry.comparingByValue(Comparator.reverseOrder()));
set.addAll(map.entrySet());

然后打印它们。

set.forEach(e-> System.out.printf("%-7s : %d%n", e.getKey(), e.getValue()));

对于您的数据,这将打印

is      : 7
the     : 4
sunny   : 2
day     : 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM