【问题标题】:How can a HashMap consist only of one entry/object?HashMap 怎么可能只包含一个条目/对象?
【发布时间】:2012-02-09 02:53:22
【问题描述】:

我想要一个只有一个键值对象的HashMap

我创建了以下HashMap

    HashMap <Integer,String>DocsCollection = new HashMap <Integer,String>();

在 HashMap 中,我希望只有一个条目/对象。 密钥类型是整数。 值类型是字符串。

例如=

每当我在文件中找到特定的单词时,我都想

  1. 增加键中的计数器

  2. 在值中添加新文件

例如假设我在DocsCollection 中搜索“Hello”这个词, 我必须为单词“Hello”的每次出现存储词频并将新文件连接到以前的值。

3 表示我在三个文件中找到了“Hello”这个词。

并且该值由找到该单词的文件组成

如果我使用 put 方法,则会在 HashMap 中创建一个新条目,从而导致密钥更改。 它不稳定。它以“1”开头,但是当我第二次找到这个词时,键会递增,然后 put 方法会插入一个带有新键的新条目 但我想只有一个条目并修改密钥。 这可以做到吗? 如何在 HashMap 中只有一个对象并且每次都修改键?

   DocsCollection.put(2,"foo.txt,hello.txt"); 

谢谢,提前

【问题讨论】:

  • 我认为您不太了解使用哈希表的目的。 (不是这个)。
  • 在我看来,地图不是你想要做的事情的正确方法......

标签: java hashmap


【解决方案1】:

试试这个方法:

DocsCollection = Collections.singletonMap(2, "foo.txt,hello.txt");

此地图无法修改,如果您想修改,请执行以下操作:

DocsCollection = Collections.singletonMap(3, "foo.txt,hello.txt");

【讨论】:

    【解决方案2】:

    Map 方法可能不是最好的。问题是您正在更改您的键值。

    请注意,最好只有List&lt;String&gt;,每次匹配单词时,只需将文件添加到列表中即可。您可以通过list.size() 轻松获得计数

    【讨论】:

    • 列表会很快吗?因为我有大约 60 个文件,我需要快速完成工作
    • 为每个单词创建列表后,我必须遍历列表并为每个单词连接列表中的每个文件。假设我有 10000 个单词,每个单词都出现在10 个文件,这意味着我将创建 10000 个列表,每个列表包含 10 个条目。之后,我必须为每个单词写入一个随机访问文件,每个单词都出现在文件中。
    • 例如"Hello" 5 "file1,file2,file3,file4,file5" 等。为了找到每个单词的文件,我必须遍历整个列表。这会不会有点慢?只有一对 不是更好吗
    • 对于 60 个条目,您可以将列表复制三次并在每次添加元素时进行侧翻,但仍然只花费很少的时间,这对您来说似乎是瞬间完成的。听说过 Knuth 关于优化的名言吗?你的瓶颈是你对这些字符串做什么,而不是你如何存储它们(如果你想找到包含该单词的所有文件,无论你如何存储文件,你仍然必须检查所有文件)。为什么你认为它甚至会开始变得重要?
    • 实际上,他的瓶颈几乎可以肯定是 IO 和字符串的 grep。但我喜欢做侧手翻的建议,所以 +1。
    【解决方案3】:

    我会尝试针对我认为您的任务提出一些不同的解决方案:

    • 你有话(hello等)
    • 您想计算在多少文件中找到它
    • 你想知道文件

    您可以为此使用MultiMap(番石榴):

    • map.put("hello", "file1.txt"); map.put("hello", "file2.txt");
    • map.keys().count("hello") - 让您知道每个单词被找到的次数
    • map.get("hello") 返回一个 Collection&lt;String&gt; 包含该单词的所有文件

    您可以在该地图中添加任意数量的单词。如果您需要每个地图一个条目,则需要 X 个地图对应 X 个单词。

    【讨论】:

    • 如果他搜索多个单词,这是一个很好的解决方案。但是一句话,列表或数组就可以了……
    【解决方案4】:

    您是否有理由需要使用 HashMap?您可以只拥有一个 int(用于计数)和一个 String 或 StringBuffer(用于文件名)并更新它们。

    或者,您可以有一个列表,每次找到某些内容时,您都可以在其中添加文件名。要获取计数,请使用 List.size()。但我看到@hvgotcodes 已经用这个想法打败了我。

    【讨论】:

      【解决方案5】:

      可以这么说,您并没有真正使用HashMap:您的计数器并不是真正的钥匙。

      根据您的解释,您似乎需要的是一个Object,代表您的搜索结果,例如:

      public class SearchResult {
           private String searchedWord;
           private long counter;
           private List<String> containingFiles;
           // ...
      }
      

      【讨论】:

      • 嗯,我需要为每个单词存储它出现的频率和文件。假设我有 10000 个单词,那么我需要创建 10000 个类。这不会花费我很多时间吗?
      • 没有。将花费您时间的是搜索单词。保持你的程序简单和优雅,你肯定会比使用不满足你初始需求的数据结构获得更好的性能。
      【解决方案6】:

      为了确保你想要的工作:

      1. 将值声明为List&lt;String&gt;
      2. 每次找到一个词时,删除原来的键/值对,并用新的内容替换它。

      类似:

      HashMap<Integer, List<String>> map = new HashMap<Integer, List<String>>();
      // some loop
      if(/* new word found */) {
         Integer key = (Integer)map.keySet().toArray()[0];
         List<String> value = (List<String>)map.get(key);
         value.add(word);
         map.remove(key);
         map.put((key + 1), value);
      }
      

      【讨论】:

        【解决方案7】:

        不是好方法。

        尝试使用Map&lt;String, Set&lt;String&gt;&gt;,其中键是关键字,值是您在其中找到关键字的文件集。然后添加到它看起来像:

        //further up
        final Map<String, Set<String>> map = new HashMap<String, Set<String>>();
        
        //then:
        public void addRef(final String keyword, final String filename)
        {
            if (!map.containsKey(keyword)) // keyword not encountered yet
                map.put(keyword, new HashSet<String>());
        
            map.get(keyword).add(filename);
        }
        

        然后,您将能够在需要时从该地图中收集信息。特别是,要收集找到关键字的文件数量,您可以:

        for (final String keyword: map.keySet())
            System.out.printf("%s was encountered %d time(s)\n",
                keyword, map.get(keyword).size());
        

        【讨论】:

          【解决方案8】:

          这里有一个使用单个键/值的映射的想法:创建映射,添加单个键值对,然后使用 Collections.unmodifiableMap() 使其不可修改。这样,就不能将其他元素添加到地图中。像这样:

          HashMap<Integer, String> docsCollection = new HashMap<Integer, String>();
          docsCollection.put(2, "foo.txt,hello.txt");
          docsCollection = Collections.unmodifiableMap(docsCollection);
          

          只有在您事先知道键/值的情况下才有效;在调用unmodifiableMap 之后,地图被有效冻结,您将无法从中添加/删除更多元素。

          现在,您在问题中提出的问题是 适合使用地图,这不是在这种情况下使用的正确数据结构。你最好有一个ArrayList&lt;String&gt;,在其中添加找到该单词的文件名,并使用列表的size() 方法来确定找到该单词的文件数。

          【讨论】:

            【解决方案9】:
            public class YourClass {
                private HashMap<Integer, String> occurrences = new HashMap<Integer, String>(1);
            
                public void addFile(String name) {
                    int count = 0;
                    String names = "";
            
                    if(occurrences.size() > 0) {
                        count = (int)(occurrences.keySet().toArray()[0]);
                        names = occurrences.get(count);
                        names += ",";
                    }
            
                    count++;
                    names += name;
                    occurrences.remove(count);
                    occurrences.put(count, names);
                }
            }
            

            当您找到一个文件(我们称之为 hello.txt),假设您在 YourClass 中找到它时,您会这样做:

            addFile("hello.txt");
            

            请注意,这是完全迟钝的>.

            采用 vakimshaar 的解决方案 ;)

            【讨论】:

            【解决方案10】:

            在历史上,标准 Java 提供的标准数据结构很少。 Apache Collections 已经在很多场合被联合使用来添加我们认为我们缺少的这些额外的数据结构。我认为这里的 OP 案例就是这些漏洞之一。是的,HashMap 不是正确的方法,并且问题被 OP 建模错误。

            对于 Map 中一个键值对的情况,通常这正是我们所需要的:Pair 或更一般的 Tuple。如果“键”和“值”对于我们需要的数据结构的每个实例通常都具有相同的数据类型,那么这将非常有效。

            我将参考this SO question(虽然有很多很好的信息,但它本身是重复的)历史上人们可能如何在 Java 中使用元组。可以使用的补充类的示例是org.apache.commons.lang3.tuple

            【讨论】:

              猜你喜欢
              • 2019-01-09
              • 1970-01-01
              • 2015-10-15
              • 2021-06-19
              • 2019-08-31
              • 1970-01-01
              • 2016-04-04
              • 2023-03-06
              • 1970-01-01
              相关资源
              最近更新 更多