简体   繁体   English

为什么没有方法可以在 Java Map 中返回给定值的键?

[英]Why is there no method for returning a Key given a Value in a Java Map?

In the Javadocs , the Map interface has methods for containsKey(Object key) , containsValue(Object value) , and get(Object key) .Javadocs 中, Map 接口具有containsKey(Object key)containsValue(Object value)get(Object key) Why is there then no method getKey(Object value) ?为什么没有方法getKey(Object value) Once you have a method to find whether the Map contains the Value, why can't you also return it?一旦有了查找 Map 是否包含 Value 的方法,为什么还不能返回它呢?
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.我知道 Map 可能包含多个任何值,但也许该方法可以返回该值的第一个实例。

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.让我们以与使用联系人列表相同的方式使用java.util.Map的实现,无论是在工作中还是在手机上。

Let's say, for instance, you want to find your friend John Smith's phone number so you can give him a call.例如,假设您想找到您朋友 John Smith 的电话号码,以便您可以给他打电话。 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.但是,Java 对映射的限制是所有键中的键必须是唯一的,因此,如果您知道一个 John Smith 和一个 John Doe,那么您插入到映射中的最后一个人将“获胜”,而您将输约翰史密斯的数据。 Silently.默默。

If you instead inserted by last name (eg 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.如果您改为按姓氏(例如 Smith)插入,然后将您认识的所有 Smiths 的值放入一个列表(John、Jane、William、Robert、Emmett),您将能够找到您要查找的内容既高效安全,而不会损坏您的联系人列表。


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.即使 Guava 的BiMap被吹捧为您的问题的“解决方案”,仍然受到键值唯一性的限制,这不是您想要的。 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 .更糟糕的是,拥有Map<List<String>, String>结构将是一场噩梦,主要是因为该键可以更改,而这根本不是任何人想要的

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.如果您希望能够获得给定值的键,那么您别无选择,只能迭代数据结构的全部内容,这(谢天谢地,或者可怕 - 选择)正是Map.Entry<K, V>提供 - 一个可迭代的条目集,以便您可以对地图中的每个元素进行自己的检查。

The Java Map interface is designed for efficient lookup of values by key. Java Map接口旨在通过键有效地查找值

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).最常用的实现之一是HashMap ,它将值放入桶中并提供恒定时间查找(假设值在桶中分布良好)。 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.另一种常见的实现是TreeMap ,在某些情况下,您的键可以轻松排序,它可能比HashMap更好。 The branches of the tree allow for quick (though log(n) , not constant-time) lookup of the keys.树的分支允许快速(虽然log(n) ,而不是恒定时间)键查找。 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.如果您需要这种可以从 Key 到 Value 或 Value 到 Key 的查找,您应该使用BiMap ,它基本上是两个映射到一个对象中 - 一个正向映射和一个反向映射。 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?"更好的问题是“如果此方法对于大多数实现来说效率低下,为什么 Java Map接口提供containsValue方法?” but I expect that is probably off-topic for SO - you might consider asking it at Computer Science .但我希望这可能与 SO 无关 - 您可以考虑在Computer Science 中询问。

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. Java 集合框架并没有实现理论上可以用所提供的类实现的所有功能——某些功能可能需要添加到特定应用程序中。 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.其次,尽管 OP 表示在多个键映射到相同值的情况下,反向查找方法可能会返回“第一个”匹配值,但映射中确实没有“第一个”的强大概念。

In the end, though, it's all speculation.不过,归根结底,这都是猜测。

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

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