【问题标题】:Sorted map not outputting sorted. Do I understand maps.排序后的地图未输出排序。我了解地图吗?
【发布时间】:2012-02-14 04:33:16
【问题描述】:

我一直在阅读地图并了解树形地图和散列、排序地图的一些差异。我试图在输出地图时对其进行排序。

我需要做的是:

  1. 获取一个文本文件并读入内容。
  2. 将其分成单独的单词。使用单词作为键,使用值作为key 在 txt 文件中出现的次数。
  3. 如果单词位于句尾,我将使其成为单独的键。例如,mymy. 是两个独立的键。

我的问题是,无论我将它声明为树、散列还是排序映射,我都无法让它以有序的方式输出/迭代。我希望它首先以最高出现的值输出,但我什至无法让它以任何顺序与键一起输出。

public static Map<String, Integer> createDictionary(String _filename)
{
    TreeMap<String, Integer> dictionary = new TreeMap<String, Integer>(); // Changed Hash to _______

    try {
          FileReader myFileReader=new FileReader(_filename); // File reader stream open
          BufferedReader myBuffReader=new BufferedReader(myFileReader);

          String str = "\0";

          while (str != null) { // While there are still strings in the file
              str = myBuffReader.readLine(); // We read a line into the str variable

              if (str != null) { // Make sure its not the last line/EOF 
                  // System.out.println(str); // Used for testing. 
                  StringTokenizer myTokenStr=new StringTokenizer(str," \t"); // Create a StringToken obj from the string

                  while (myTokenStr.hasMoreTokens()) {
                      String tokStr = myTokenStr.nextToken(); // Each token is put into an individual string
                      // System.out.println(tokStr);

                      if (dictionary.containsKey(tokStr)) {
                          int value = dictionary.get(tokStr); // Add one to the integer value
                          // dictionary.remove(tokStr); // Was doing this way but just using put method works 
                          // dictionary.put(tokStr, value + 1);
                          dictionary.put(tokStr, value + 1);
                      }
                      else {
                          dictionary.put(tokStr, 1); // Add the string as the key with an int value of one for the value
                      }
                  }
              }
          }

          myBuffReader.close(); // Close stream
          myFileReader.close(); // Close stream
      }
      catch (FileNotFoundException e) {
          System.out.println("File Not Found");
      }
      catch (IOException e) { }

      // System.out.println(dictionary.entrySet());

      return dictionary;
}

【问题讨论】:

  • 首先,您确定要在" \t" 上进行标记吗?当您说“分解成单词”时,默认标记字符串在一般情况下似乎更匹配,即StringTokenizer(str)您不会以标记化的方式匹配换行符。你到底是如何迭代的? (另外,如果你想对它进行排序,忘记 HashMap,TreeMap 是唯一的方法)
  • Stiles... 它以正确的字数输出正确的单词,但这些单词不是按字母顺序排列的,或者值/字数是按顺序排列的。它像哈希图一样随机。 Irfy .... "\t" 上的标记应该在空格和制表符上标记。唯一的另一个是行尾,并且已经处理好了。我可能错了,但它与 c++ tokinize 类似,并且它适用于我发送的测试用例。

标签: java map


【解决方案1】:

您的地图按字母顺序排序,而不是按出现次数。您需要在初始解析后对地图进行后处理。我建议:

  1. 将文件解析为HashMap&lt;String, Integer&gt;
  2. 遍历HashMap,并将元素添加到TreeMap&lt;Integer, Set&lt;String&gt; &gt;(见下文)。
  3. 输出TreeMap

您可以通过以下方式实现第 2 步:

TreeMap<Integer, Set<String> > treeMap = new TreeMap<Integer, Set<String> > ();
for (Map.Entry<String, Integer> entry: hashMap) {
    Set<String> set = treeMap.get(entry.value());
    if (set == null) {
        set = new TreeSet<String>();
        treeMap.put(entry.value(), set);
    }
    set.add(entry.key());
}

在这里使用TreeSet 按字母顺序对出现次数相同的单词进行排序,但您可以使用任何其他SetList

对于步骤 3 中的降序:

for (Map.Entry<Integer, Set<String> > entry: treeMap.descendingMap())
    for (String word: entry.getValue())
        System.out.println(String.format("%d: %s", entry.getKey(), word));

应该可以的。

【讨论】:

  • 如果两个单词的计数相同会怎样?
  • 好点。我想如果没有TreeMap&lt;Integer, List&lt;String&gt; &gt; 和一些额外的代码来创建列表并在它存在时附加到它,它将无法工作。
【解决方案2】:

这是 TreeMap 的文档,取自其 Javadoc:

公共类 TreeMap 扩展 AbstractMap 实现 NavigableMap、Cloneable、Serializable 基于红黑树的 NavigableMap 实现。 地图按顺序排列 到其键的自然顺序,或通过在地图创建时提供的比较器 时间,取决于使用的构造函数。

在您的情况下,键将是字符串,您应该期望迭代将显示地图根据其“自然顺序”进行排序。下面是一个由字符串键和整数值组成的 TreeMap 生成的输出示例:

Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("Hello", Integer.valueOf(8));
map.put("Abraham", Integer.valueOf(81));
map.put("Smell", Integer.valueOf(-1));
map.put("Carpet", Integer.valueOf(4));
map.put("Sex", Integer.valueOf(23));

for(String key: map.keySet()) {
    System.out.printf("Map entry %s: %d\n", key, map.get(key));
}

输出:

Map entry Abraham: 81
Map entry Carpet: 4
Map entry Hello: 8
Map entry Sex: 23
Map entry Smell: -1

如您所见,遍历地图的键会产生有序的结果。此顺序由 String 的自然顺序定义。不幸的是,您不能实现对值进行排序的 SortedMap,我相信这是您想要做的。但是,您可以在地图之外对地图中的条目进行排序。在其他 SO 帖子中查看更多详细信息:TreeMap sort by value

【讨论】:

  • 如果我将我的地图更改为 TreeMaps 并使用与发布相同的方式来遍历它,它不会像你展示的那样给出和排序输​​出。这是我的问题的一部分。从我读到的到我看到的,它们是不一样的。查看我的代码是否有一些关于我如何迭代可能正在执行的地图的内容。我完全不明白迭代器的使用。
  • @aaronburns - 你的代码看起来基本没问题。尝试在您的字符串上调用trim(),然后再将它们存储到地图中。
【解决方案3】:

Map 是这类事情的一种混乱抽象,但我将抛弃 Guava 的 Multiset 作为解决此用例的一种方式,因为它明确设计用于“计算事物的发生次数。 "

特别是,

return Multisets.copyHighestCountFirst(HashMultiset.copyOf(listOfWords));

返回一个Multiset,它在listOfWords 中按频率降序对元素进行迭代。

顺便说一句,关于 SO 有很多问题,与按 values 而不是键对 map 进行排序有关,但我更喜欢 this solution

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-30
    • 2020-04-22
    • 2011-06-15
    • 2014-02-01
    • 1970-01-01
    • 2018-01-25
    • 2015-09-23
    • 2013-01-16
    相关资源
    最近更新 更多