【问题标题】:Case Insensitive Dictionary with char key in C#C#中带有char键的不区分大小写字典
【发布时间】:2014-12-18 08:33:38
【问题描述】:

如果我有一个Dictionary<char,...>,是否可以使方法 ContainsKey 不区分大小写?

我知道,在Dictionary<string,...>中使用了StringComparer.InvariantCultureIgnoreCase,但是当字典中的key是char类型时该怎么办?

【问题讨论】:

  • 一个非常简单的选项是为'a'和'A'添加相同的值,例如。但将其视为一种解决方法。
  • 您的“我知道..”的参考:stackoverflow.com/questions/13988643/…
  • 为了清楚起见 - 您是在寻找不区分大小写字典的解决方案(因此 myDict['a'] 相当于 myDict['A']),还是一个案例-不敏感的 ContainsKey 方法(所以 myDict.ContainsKey('a') 无论是否定义了 'a' 或 'A' 或两者都返回 true ?)
  • @MickyDuncan 确实,这就是为什么我没有将其发布为 aswer 的原因。但是,它简单且易于实现。毕竟,如果它们都被使用的话,它只会多占用 26 个位置 - 不是那么多!
  • @Avner Shahar-Kashtan 我有只有大写字母的字典,但是当我使用 ContainsKey('a') 时它必须工作。

标签: c# dictionary collections


【解决方案1】:

Dictionary 类有一个构造函数,它接受任何IEqualityComparer。您需要做的是实现一个简单的不区分大小写的IEqualityComparer<char> 并将其传递给构造函数,它会在评估密钥时使用。

这是一个类似的问题,用于在不区分大小写的情况下实现 IComparer<char>IEqualityComparer 几乎相同:

【讨论】:

  • 它会使 ContainsKey 不区分大小写(就像 OP 想要的那样)或整个字典?
  • 嗯,我没有考虑到 OP 希望 only ContainsKey 不敏感的可能性。这似乎是一个奇怪的要求。
  • 看起来 OP 想要同时添加 'x' 和 'X' 但他想要单个操作来检查这些条目是否存在
  • 让我们看看OP怎么说。
  • 我的字典只有大写字母(高效记忆),但使用 ContainsKey 方法时,我有时会尝试检查小写字母,有时会检查大写字母。
【解决方案2】:

您可以实现自己的比较器:

public class CharComparer : IEqualityComparer<char>
{
     public bool Equals(char c1, char c2)
     {
          return char.ToLowerInvariant(c1) == char.ToLowerInvariant(c2);
     }
     public int GetHashCode(char c1)
     {
          return char.ToLowerInvariant(c1).GetHashCode();
     }

}

并将其传递给构造函数:

var dict = new Dictioanry<char, object>(new CharComparer());

【讨论】:

    【解决方案3】:

    你也可以实现一个扩展方法:

    public static bool ContainsKeyInsensitive(this Dictionary<char, ...> dict, char c)
    {      
      return dict.ContainsKey(char.ToUpper(c)) || dict.ContainsKey(char.ToLower(c));
    }
    

    【讨论】:

    • 这几乎抵消了字典在 O(1) 查找中的任何优势,将它们转换为 O(n)。这不是一个好的解决方案。
    • 这里唯一正确的答案。但实施并不是最好的。只需对大写和小写字符进行两次查找,而不是检查所有键
    • derape:不,字典使用哈希表进行高效查找:stackoverflow.com/questions/730620/how-does-a-hash-table-work
    • @Sergey 我相信使用char 时甚至不需要两次查找。请参阅我的答案以了解更多详细信息。
    【解决方案4】:

    你也可以调用两次。

    if (dict.ContainsKey(char.ToLowerInvariant(ch)) || dict.ContainsKey(char.ToUpperInvariant(ch)))
    {
        ...
    }
    

    作为扩展方法,变成:

    public static bool ContainsKeyInsensitive<T>(this Dictionary<char, T> dict, char ch)
    {
        return dict.ContainsKey(char.ToLowerInvariant(ch)) || dictionary.ContainsKey(char.ToUpperInvariant(ch));
    }
    

    【讨论】:

      【解决方案5】:

      起初;我知道接受的答案有效,这是一个很好的答案。然而,我发现不需要实现任何扩展方法/附加逻辑来达到预期的结果。

      我想您使用字典是因为您想将键映射到特定值 - 这正是它们的用途。如果你只用它来查找键,你应该使用HashSet&lt;char&gt;

      好吧,话虽如此,让我们来看看char 的三个选项;

      • 您愿意将大写以及映射为小写,为大写和小写赋予一个不同的值。
      • 您愿意映射小写,这意味着大写与大写具有相同的值。
      • 您愿意映射大写,这意味着小写与大写具有相同的值。

      我会解释这三个。对于所有选项,请考虑不知道输入 char 是大写还是小写。

      选项1;不同的键,不同的值。

      映射两者是要走的路。如果您需要 'a''A' 的不同值,无论如何您都需要添加它们。因此,您可以只使用.ContainsKey(),它将返回所需的结果。此选项可能不符合您的需要,因为您正在寻找不区分大小写的字典。

      选项 2:小写与大写的值相同。

      如果您想随时获取小写值,只需致电.ContainsKey(yourChar.ToLower())

      选项 3:大写与小写的值相同。

      同样的故事!只是现在,使用.ContainsKey(yourChar.ToUpper()) 来获得正确的结果。由于您在评论中发布了您的字典只有大写字符,这应该是要走的路。

      不区分大小写的Dictionary&lt;string,T&gt; 也是如此;只映射小写或大写(小写是我的偏好,但这是您自己的选择)。

      下面的代码 sn-p 应该演示它是如何工作的。

      Dictionary<char, object> dic = new Dictionary<char, object>();
      
      public object GetIfKeyExists(char c)
      {
          // Consider c = 'a' or c = 'A'
      
          // Option 1: Both have different values, so they should be existing anyway.
          if (dic.ContainsKey(c)) return dic[c];
      
          // Option 2: Only lowercase is mapped.
          char correctInput = c.ToLower();
          if (dic.ContainsKey(correctInput)) return dic[correctInput];
      
          // Option 3: Only uppercase is mapped.
          char correctInput = c.ToUpper();
          if (dic.ContainsKey(correctInput)) return dic[correctInput];
      }
      

      那么,最后,我还是想知道你为什么要检查上 下。如果返回 true,它会提供什么信息?您仍然不知道 哪个 确切存在 - 这就是为什么您应该选择映射大写或小写并坚持使用它。

      【讨论】:

        【解决方案6】:

        只需像这样定义字典:

        Dictionary<string, int> Dict = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-09
          • 2017-12-01
          • 2020-02-18
          • 2012-12-08
          • 2018-01-26
          • 2018-12-30
          相关资源
          最近更新 更多