Java 无论情况如何,如何检查地图中的键?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3092710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check for key in a Map irrespective of the case?
提问by GuruKulki
I want to know whether a particular key is present in a HashMap, so i am using containsKey(key) method. But it is case sensitive ie it does not returns true if there is a key with Name and i am searching for name. So is there any way i can know without bothering the case of the key?
我想知道 HashMap 中是否存在特定键,因此我使用 containsKey(key) 方法。但它区分大小写,即如果有一个带 Name 的键并且我正在搜索 name,它不会返回 true。那么有什么方法可以让我知道而不打扰钥匙的情况?
thanks
谢谢
采纳答案by Andrzej Doyle
Not with conventional maps.
不适用于传统地图。
"abc" is a distinct string from "ABC", their hashcodes are different and their equals() methods will return false with respect to each other.
"abc" 是一个与 "ABC" 不同的字符串,它们的哈希码不同,它们的 equals() 方法将相对于彼此返回 false。
The simplest solution is to simply convert all inputs to uppercase (or lowercase) before inserting/checking. You could even write your own Map
wrapper that would do this to ensure consistency.
最简单的解决方案是在插入/检查之前简单地将所有输入转换为大写(或小写)。您甚至可以编写自己的Map
包装器来确保一致性。
If you want to maintain the case of the key as provided, but with case-insensitive comparison, you could look into using a TreeMapand supplying your own Comparator that will compare case-insensitively. However, think hard before going down this route as you willend up with some irreconcilable inconsistencies - if someone calls map.put("abc", 1)
then map.put("ABC", 2)
, what case is the key stored in the map? Can you even make this make sense? Are you comfortable with the fact that if someone wraps your map in a standard e.g. HashMap
you'll lose functionality? Or that if someone happens to be iterating through your keyset anyway, and does their own quick "contains" check by using equals()
you'll get inconsistent results? There will be lots of other cases like this too. Note that you're violating the contract of Mapby doing this (as key equality is defined in terms of the equals() method on the keys) so it's really not workable in any sense.
如果您想保持提供的键的大小写,但不区分大小写的比较,您可以考虑使用TreeMap并提供您自己的比较器,该比较器将不区分大小写进行比较。但是,在沿着这条路线走之前请仔细考虑,因为您最终会遇到一些不可调和的不一致 - 如果有人拨打map.put("abc", 1)
then map.put("ABC", 2)
,地图中存储的密钥是什么情况?你能说得通吗?如果有人将您的地图包装在标准中,例如HashMap
您将失去功能,您是否对此感到满意?或者,如果有人碰巧正在遍历您的键集,并且他们自己的快速“包含”检查是否通过使用equals()
您会得到不一致的结果?还会有很多其他类似的案例。 请注意,您这样做违反了 Map 的合同(因为键相等性是根据键上的 equals() 方法定义的),因此它在任何意义上都行不通。
Maintaining a strict uppercase map is mucheasier to work with and maintain, and has the advantage of actually being a legal Map implementation.
维护严格的大写映射更容易使用和维护,并且具有实际上是合法映射实现的优势。
回答by Péter T?r?k
Map
uses equals
and hashCode
to test for key equality, and you can't overwrite these for String
. What you could do is define your own Key class which contains a string value, but implements equals
and hashCode
in a case insensitive way.
Map
使用equals
和hashCode
来测试密钥相等性,并且您不能为String
. 你可以做的是定义包含一个字符串值,你自己的Key类,但工具equals
并hashCode
在不区分大小写的方式。
回答by tim_yates
There's a CaseInsensitiveMap classin Apache commons
Apache commons 中有一个CaseInsensitiveMap 类
回答by Bozho
You can use a TreeMap
with a custom, case-insensitive Comparator
(that uses String.compareToIgnoreCase()
)
您可以将 aTreeMap
与自定义的、不区分大小写的Comparator
(使用String.compareToIgnoreCase()
)
For example:
例如:
Map<String, Something> map =
new TreeMap<String, Something>(CaseInsensitiveComparator.INSTANCE);
class CaseInsensitiveComparator implements Comparator<String> {
public static final CaseInsensitiveComparator INSTANCE =
new CaseInsensitiveComparator();
public int compare(String first, String second) {
// some null checks
return first.compareToIgnoreCase(second);
}
}
Update: it seems that String
has already defined this Comparator
as a constant.
更新:似乎String
已经将其定义Comparator
为常量。
回答by BalusC
Use a TreeMap
which is constructed with String#CASE_INSENSITIVE_ORDER
.
使用由TreeMap
构造的a String#CASE_INSENSITIVE_ORDER
。
Map<String, String> map = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
map.put("FOO", "FOO");
System.out.println(map.get("foo")); // FOO
System.out.println(map.get("Foo")); // FOO
System.out.println(map.get("FOO")); // FOO
回答by Nivas
create your own wrapper of string class, implement equals and hashcode, use this as the key in the hashmap:
创建您自己的字符串类包装器,实现equals 和hashcode,将其用作hashmap 中的键:
class MyStringKey
{
private String string;
public String getString()
{
return string;
}
public void setString(String string)
{
this.string = string;
}
public boolean equals(Object o)
{
return o instanceof MyStringKey && this.equalsIgnoreCase(((MyStringKey)o).getString());
}
public boolean hashCode()
{
return string.toLowerCase().hashcode(); //STRING and string may not have same hashcode
}
}
回答by gustafc
To preserve the Map
invariants, you could just make your own keys. Implement sensible hashCode
/equals
and you're good to go:
为了保留Map
不变量,您可以制作自己的密钥。实施明智的hashCode
/equals
就可以了:
final class CaseInsensitive {
private final String s;
private final Local lc;
public CaseInsensitive (String s, Locale lc) {
if (lc == null) throw new NullPointerException();
this.s = s;
this.lc = lc;
}
private s(){ return s == null ? null : s.toUpperCase(lc); }
@Override
public int hashCode(){
String u = s();
return (u == null) ? 0 : u.hashCode();
}
@Override
public boolean equals(Object o){
if (!getClass().isInstance(o)) return false;
String ts = s(), os = ((CaseInsensitive)other).s();
if (ts == null) return os == null;
return ts.equals(os);
}
}
// Usage:
Map<CaseInsensitive, Integer> map = ...;
map.put(new CaseInsensitive("hax", Locale.ROOT), 1337);
assert map.get(new CaseInsensitive("HAX", Locale.ROOT) == 1337;
Note:Not everyone in the whole world agrees about what is uppercase of what - a famous example is that the upper-case version of "i" in Turkish is "?", not "I".
注意:不是全世界的每个人都同意什么是什么的大写 - 一个著名的例子是土耳其语中“i”的大写版本是“?”,而不是“I”。
回答by Thorbj?rn Ravn Andersen
The easiest way is to fold the keys yourself when inserting them and looking them up. I.e.
最简单的方法是在插入和查找时自己折叠钥匙。IE
map.put(key.toLowerCase(), value);
and
和
map.get(key.toLowerCase());
You could subclass e.g. HashMap to get your own class with these, if you want this automatically done.
如果您希望自动完成,您可以子类化例如 HashMap 以获得您自己的类。
回答by KisnardOnline
In an attempt to present an answer that matches your question's requirement "without bothering the case of the key"...
试图提出一个符合您问题要求的答案,“不打扰钥匙的情况”......
This answer may be tedious if you add into your map in many, many places. In my example it only happens when a user creates a new character (in my game). Here is how I handled this:
如果您在许多地方添加到地图中,这个答案可能会很乏味。在我的示例中,它仅在用户创建新角色时发生(在我的游戏中)。这是我处理这个的方法:
boolean caseInsensitiveMatch = false;
for (Map.Entry<String, Character> entry : MyServer.allCharacterMap.entrySet()) {
if (entry.getKey().toLowerCase().equals(charNameToCreate.toLowerCase())){
caseInsensitiveMatch = true;
break;
}
}
Of course this requires looping through my large ConcurrentHashMap, but works for me.
当然,这需要遍历我的大型 ConcurrentHashMap,但对我有用。