【问题标题】:Find a object key from a HashMap从 HashMap 中查找对象键
【发布时间】:2011-03-09 16:36:10
【问题描述】:

我有一个 HashMap,键是我自己的对象,键是字符串的 ArrayList。有没有办法在不迭代地图的情况下从地图中获取与另一个对象相等的关键对象。请注意,我的对象已经实现了 equals & hashcode。它只使用类的 2 个属性进行比较。我试图在地图的键中找到的另一个对象具有这两个属性相等但其他属性可能在地图的键中不同。

//The actual map
private HashMap<FileDetail, ArrayList<String>> map = new HashMap<FileDetail, ArrayList<String>>();
//object to search in above map without iteration.
FileDetail file = some object;

我想在地图的键中获取“文件”对象的引用。

【问题讨论】:

  • 你想用什么信息来找到你的钥匙?
  • 澄清一下,您想检索键本身而不是键引用的值?
  • 是的,我想先检索密钥,然后根据密钥对象的状态使用该值。
  • 我不希望在我的情况下使用任何外部 API。我可以请帮助 java API 类。

标签: java collections


【解决方案1】:

不,你不能那样做。 HashMap 应该以另一种方式工作:你有钥匙,你正在寻找对象。

如果你有一个对象并且你想找到关键,那么你的逻辑可能有问题并且你寻找错误的方向来解决你的问题。

【讨论】:

  • 就像我有一张地图,其中的关键对象正在被某个改变状态的任务处理。我还有另一个任务,它有一个新的对象。因此,在发送我的新对象进行处理之前,我想从地图中检查状态。如果它已经被处理,那么我将忽略从某个地方收到的新对象。
  • 你是对的 Krtek & 谢谢。该地图应该基于密钥。最后我决定迭代,因为我无法添加任何新库。
【解决方案2】:

如果你不想遍历keySet,那么你可以使用Guava'sBiMap。 biMap 有一个反向视图,它是另一个包含反转键和值的 bimap。这就是你将如何使用它:

BiMap<FileDetail, ArrayList<String>> biMap = HashBiMap.create();

//object to search in above map without iteration.
FileDetail file = some object;

FileDetail key = biMap.inverse().get(biMap.get(file));

【讨论】:

    【解决方案3】:

    如果您确实需要在不迭代 keySet 的情况下执行此操作(例如,因为映射非常大),我建议将键和列表都存储为映射中的值。要么创建一些封装两者的特定类,要么使用简单的对类。地图如下所示:

    Map<FileDetail, Pair<FileDetail, List<String>>>
    

    如果您无法更改映射的类型,您可以使用第二个Map&lt;FileDetail, FileDetail&gt;,其中键和值始终是相同的对象。

    【讨论】:

      【解决方案4】:

      这个问题已经有五年了,但我今天也有同样的问题,并找到了这个页面。我想我会分享我决定使用的解决方案,该解决方案在任何现有答案中都没有描述,并避免迭代地图中的所有键。 (请保持温和;这是我在 SO 上的第一篇文章。很难找到我可以回答但还没有答案的问题。此外,我迄今为止必须提出的每个问题都已经在 SO 上提出过。我一直在使用SO 多年,无法对答案发表评论或投票。)

      如前所述,地图的设计目的是当您拥有一个键时,您可以查找一个值。在这种情况下,答案是将键也用作值,这样当您使用任意键(equals 您的原始键但不一定是 == 对它)执行查找时,您将返回原钥匙。那么问题来了,如何获得你最初想要的价值。

      我的解决方案取决于控制用于键的类和地图的控制,并能够重新定义它们,这似乎是 OP 的情况。在 OP 的示例中,这将是对 FileDetail 类和私有 map 变量的控制。假设有这样的控制,FileDetail 类将被修改为包含类型为ArrayList&lt;String&gt; 的成员变量,对于下面的示例代码,我将调用list,并带有相关的setter 和getter 方法。对于私有的map 变量,它会这样定义:

      private HashMap<FileDetail, FileDetail> map = new HashMap<>();
      

      现在,当您想在映射中put 一个新的ArrayList&lt;String&gt; 对象,分配给特定的FileDetail 键时,您将ArrayList&lt;String&gt; 对象分配给FileDetailArrayList&lt;String&gt; 成员变量而是将FileDetail 对象放在map 中。

      public void putInMap(FileDetail fd, ArrayList<String> al) {
          // Ignoring null conditions for simplicity...
          fd.setList(al);
          map.put(fd, fd);
      }
      

      稍后,当您得到一些任意的 FileDetail 对象(一个以 equals 为键但不一定是 == 的对象),并且您想要关联的键时,只需进行正常查找即可:

      FileDetail otherFd = getArbitraryFileDetail();
      FileDetail originalKeyFd = map.get(otherFd);
      

      并在执行上述操作后获取关联的ArrayList&lt;String&gt;

      ArrayList<String> al = originalKeyFd.getList();
      

      当然,这一切都取决于 FileDetail 类的 equalshashCode 方法的实现,但 OP 已经根据需要定义了这些方法。

      希望这可以帮助像我一样访问此页面并遇到类似情况的任何人。

      【讨论】:

        【解决方案5】:

        您可能正在寻找一个双向映射,Apache Commons Collections 将其作为库的一部分包含(我确信还有其他实现。)顾名思义,双向映射是一个映射,但编写为使按键或按值高效查找。

        【讨论】:

          【解决方案6】:

          在 Java 中,HashMap 将键与值相关联,而不是相反。

          您可以使用HashMap.keySet() 检索所有键的Set,或者使用HashMap.entrySet() 遍历所有条目:

          for (Entry <FileDetail, ArrayList<String>> entry : map.entrySet()) {
              FileDetail key = entry.getKey();
              if (shouldProcess(key)) {
                  ArrayList<String> list = entry.getValue();
                  processList(list);
              }
          }
          

          【讨论】:

          • 有其他限制我选择只使用迭代。不过,我喜欢 Philipp Wendler 将键值封装在对象中的答案。
          【解决方案7】:

          我们通过将keyset转换为ArrayList,在不迭代HashMap的keyset的情况下,从Hashmap中获取key对象。这是一个简单的例子:

          //Creating hashmap
          HashMap<String, String> map = new HashMap<String, String>();
          
          //Adding elements into the map  
          map.put("1", "Amit");
          map.put("2", "Ananth");
          map.put("3", "Sunil");
          
          //Get the list from keyset
          ArrayList myKeyList = new ArrayList(map.keySet());
          
          //object to search in above map without iteration.
          String myobj = "3";
          System.out.println(myKeyList.get(myKeyList.indexOf(myobj)));
          

          【讨论】:

          • 确实遍历所有键的列表。 List.indexOf() 需要这样做才能找到对象。将 keySet 复制到列表中也需要在地图上进行迭代。仅迭代 keySet 会比您的解决方案便宜得多。
          • 将键集复制到列表中将处理 System.arraycopy() 方法。 /** * @com.intel.drl.spec_ref */ public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { VMMemoryManager.arrayCopy(src, srcPos, dest, destPos, length); }。这样会更快。
          猜你喜欢
          • 1970-01-01
          • 2021-05-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-11
          • 2020-01-20
          相关资源
          最近更新 更多