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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:24:05  来源:igfitidea点击:

How to check for key in a Map irrespective of the case?

java

提问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 Mapwrapper 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. HashMapyou'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

Mapuses equalsand hashCodeto 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 equalsand hashCodein a case insensitive way.

Map使用equalshashCode来测试密钥相等性,并且您不能为String. 你可以做的是定义包含一个字符串值,你自己的Key类,但工具equalshashCode在不区分大小写的方式。

回答by Bozho

You can use a TreeMapwith 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 Stringhas already defined this Comparatoras a constant.

更新:似乎String已经将其定义Comparator为常量。

回答by BalusC

Use a TreeMapwhich 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 Mapinvariants, you could just make your own keys. Implement sensible hashCode/equalsand 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,但对我有用。