英文:
Why is there no method for returning a Key given a Value in a Java Map?
问题
在Javadocs中,Map接口具有用于containsKey(Object key)
、containsValue(Object value)
和get(Object key)
的方法。那么为什么没有一个方法叫做getKey(Object value)
呢?一旦有了一种查找Map是否包含该值的方法,为什么不能将其返回呢?我明白Map可能包含多个相同的值,但或许该方法可以返回该值的第一个实例。
英文:
In the Javadocs, the Map interface has methods for containsKey(Object key)
, containsValue(Object value)
, and get(Object key)
. Why is there then no method getKey(Object value)
? Once you have a method to find whether the Map contains the Value, why can't you also return it?
I understand it's possible for the Map to contain more than one of any Value, but perhaps the method could return the first instance of the value.
答案1
得分: 3
让我们以与在工作中或手机上保存联系人列表相同的方式使用java.util.Map
的实现。
假设,例如,您想要查找您朋友John Smith的电话号码,以便您可以给他打电话。您有机会通过名字或姓氏之一进行搜索。
然而,Java对映射的限制是,键必须在所有键中是唯一的,因此,如果您认识John Smith和John Doe,那么您插入映射的最后一个人将会“获胜”,并且您将丢失John Smith的数据。默默无闻。
如果您改为通过姓氏(例如Smith)插入,然后将您认识的所有Smith的值放入列表中(John、Jane、William、Robert、Emmett),您将能够高效且安全地找到您要查找的内容,而不会有损坏联系人列表的风险。
您不能通过值进行搜索的原因是,值在存储在键值对数据结构中时没有显式的唯一性保证。甚至Guava的BiMap
,被吹捧为解决您问题的“解决方案”,仍然受到在键和值之间保持唯一性的限制,这不是您想要的。更糟糕的是,拥有一个Map<List<String>, String>
的结构会是一场噩梦,主要是因为该键可以更改,这绝对不是任何人想要的。
如果您想要能够根据值获取键,则除了迭代整个数据结构的内容别无选择,这恰好是Map.Entry<K, V>
所提供的 - 可迭代的条目集,以便您可以对映射中的每个元素进行自己的检查。
英文:
Let's use an implementation of java.util.Map
in the same way you'd use a contacts list, either at your job or one you keep on your phone.
Let's say, for instance, you want to find your friend John Smith's phone number so you can give him a call. You are given the chance to search either by first name or by last name.
However, Java's limitation on maps is that the key must be unique across all keys, and thus, if you know a John Smith and a John Doe, then the last person you inserted into the map will "win", and you'll lose the data of John Smith. Silently.
If you instead inserted by last name (e.g. Smith), and were to then put values of all of the Smiths you knew into a list (John, Jane, William, Robert, Emmett), you would be able to find what you were looking for both efficiently and safely, without the risk of damaging your contact list.
The reason that you can't search by value is that a value has no explicit guarantee of uniqueness when stored in a key-value pair data structure. Even Guava's BiMap
, which has been touted as a "solution" to your problem, still suffers from the limitation of uniqueness across keys and values, which ain't what you want. Worse still, it would be a nightmare to have a structure of Map<List<String>, String>
, chiefly because that key can change which is not what anyone wants at all.
If you want to be able to get a key given a value, then you have no choice but to iterate the entire contents of the data structure, which (thankfully, or frightfully - take your pick) is exactly what Map.Entry<K, V>
provides - an iterable entry set so that you can do your own checks on each element in the map.
答案2
得分: 2
Java Map
接口旨在通过键高效查找值。
其中最常用的实现之一是 HashMap
,它将值放入桶中,并提供常数时间的查找(假设值在桶中分布良好)。这意味着查找键非常快速 - 你可以在常数时间内对键进行哈希处理,几乎立即查看是否有匹配的值。然而,为了检查值的存在,你需要遍历所有值。
另一个常见的实现是 TreeMap
,在某些情况下可以优于 HashMap
,特别是当你的键可以轻松排序时。树的分支允许快速(尽管是log(n)
,不是常数时间)查找键。然而,再次注意,查找值需要遍历树的每个节点,直到找到一个值。
如果你需要这种从键到值或从值到键的查找,你应该使用 BiMap
,它基本上是两个映射合并为一个对象 - 一个正向映射和一个反向映射。Google 的 Guava 库有一个,我过去使用过。
更好的问题可能是,“为什么 Java Map
接口提供 containsValue
方法,如果这个方法对大多数实现来说都不太高效?” 但我预计这可能不适合在 Stack Overflow 上讨论 - 你可以考虑在计算机科学上提问。
英文:
The Java Map
interface is designed for efficient lookup of values by key.
One of the most common implementations used is a HashMap
, which puts the values into buckets and provides constant-time lookup (assuming the values are well-distributed in the buckets). This means that looking up a key is extremely fast - you can hash the key in constant time and almost immediately see if there is a matching value. However, in order to check for the presence of a value, you need to iterate through all of the values.
Another common implementation is the TreeMap
, which can be better than the HashMap
in some cases where your keys can be easily sorted. The branches of the tree allow for quick (though log(n)
, not constant-time) lookup of the keys. However, once again, looking up the values requires traversing every node of the tree until a value is found.
If you need this kind of lookup that can go from Key to Value or Value to Key, you should be using a BiMap
, which is basically two maps rolled into one object - one forward map and one reverse map. Google's Guava library has one that I have used in the past.
The better question would be "why does the Java Map
interface provide a containsValue
method if this method will be inefficient for most implementations?" but I expect that is probably off-topic for SO - you might consider asking it at Computer Science.
答案3
得分: 0
Java集合框架并未实现可以通过提供的类实现的每个理论上可能的功能,某些功能可能需要在特定应用中添加。为什么选择某个功能集而不是另一个功能集并没有确凿的答案,只有框架的原始设计者才知道。
然而,在这种情况下,可以推测至少有两个理由不建议提供反向(值->键)查找功能。首先,开发人员可能不清楚相对于正向(键->值)查找,它是否一定会比较低效。如果你真的必须使用迭代来实现它,这一点会很快变得明显。
其次,尽管原作者说反向查找方法可能会在多个键映射到相同值的情况下返回“第一个”匹配值,但在映射中并没有关于“第一个”的健壮概念。
然而,最终这只是推测。
英文:
The Java collections framework does not implement every feature that could theoretically be actualized with the classes provided -- some features may need to be added in a specific application. There's no knock-down right answer to why one set of features was chosen over another -- only the original designers of the framework know that.
In this case, though, it seems plausible to conjecture that providing a reverse (value->key) lookup would be a bad idea for at least two reasons. First, it wouldn't be obvious to developers that it would necessarily be inefficient compared to the forward (key->value) lookup. It would become obvious pretty quickly if you actually have to implement it using iteration.
Second, although the OP says that the reverse lookup method might return the "first" matching value in the case where multiple keys map to the same value, there really isn't a robust notion of "first" in a map.
In the end, though, it's all speculation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论