使HashSet <string>不区分大小写

我有HashSet参数的方法。 我需要做大小写不敏感包含在其中:

public void DoSomething(HashSet<string> set, string item) { var x = set.Contains(item); ... } 

是否有任何方法使现有的HashSet不区分大小写(不要创build新的)?

我正在寻找最佳性能的解决scheme。

编辑

包含可以被多次调用。 所以IEnumerable扩展对我来说是不可接受的,因为性能比本地的HashSet Contains方法要低。

既然,回答我的问题是NO,这是不可能的,我创build并使用了下面的方法:

 public HashSet<string> EnsureCaseInsensitive(HashSet<string> set) { return set.Comparer == StringComparer.OrdinalIgnoreCase ? set : new HashSet<string>(set, StringComparer.OrdinalIgnoreCase); } 

HashSet<T>构造函数有一个重载,允许您传递一个自定义的IEqualityComparer<string> 。 已经为静态的StringComparer类定义了其中的一些,其中一些忽略大小写。 例如:

 var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase); set.Add("john"); Debug.Assert(set.Contains("JohN")); 

在构buildHashSet<T>的时候你必须做这个改变。 一旦存在,就不能更改它正在使用的IEqualityComparer<T>


只要你知道,默认情况下(如果你没有传入任何IEqualityComparer<T>HashSet<T>构造函数),它就会使用EqualityComparer<T>.Default


编辑

这个问题似乎已经改变了,我发布我的答案。 如果您必须在现有区分大小写的 HashSet<string>执行不区分大小写的search,则必须执行线性search:

 set.Any(s => string.Equals(s, item, StringComparison.OrdinalIgnoreCase)); 

这是没有办法的。

您不能神奇地使大小写敏感的HashSet(或字典)以不区分大小写的方式行事。

如果不能依赖传入的HashSet来区分大小写,则必须在函数内重新创build一个。

最紧凑的代码 – 使用现有的构造函数 :

 var insensitive = new HashSet<string>( set, StringComparison.InvariantCultureIgnoreCase); 

请注意,复制HashSet和遍历所有项目一样昂贵,所以如果你的函数只是search,那么遍历所有项目会更便宜(O(n))。 如果您的函数多次调用来进行单个不区分大小写的search,则应该尝试将适当的HashSet传递给它。

HashSet被devise成根据其散列函数和等式比较器来快速find元素。 你所要求的是真的find一个匹配“其他”条件的元素。 想象一下,你有一个Set<Person>对象只使用Person.Name来进行比较,你需要find一个Person.Age给定值的Person.Age

重点是你需要迭代集合的内容来find匹配的元素。 如果你经常这样做,你可能会创build一个不同的Set,在你的情况下使用不区分大小写的比较器,但是你必须确保这个阴影集与原始的同步。

到目前为止的答案基本上是上述的变化,我想补充说明这个基本问题。

假设你有这个扩展方法:

 public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) { return new HashSet<T>(source); } 

你可以使用这个:

 set = set.Select(n => n.ToLowerInvariant()).ToHashSet(); 

或者,你可以这样做:

 set = new HashSet(set, StringComparer.OrdinalIgnoreCase); //or InvariantCultureIgnoreCase or CurrentCultureIgnoreCase 

HashSet的构造函数可以采用另一种IEqualityComparer ,它可以覆盖如何确定相等性。 请看这里的构造函数列表。

StringComparer类包含一串用于string的IEqualityComparers静态实例。 特别是,你可能对StringComparer.OrdinalIgnoreCase感兴趣。 这里是StringComparer的文档。

请注意,另一个构造函数接受一个IEnumerable ,所以你可以从你的旧构造函数构造一个新的HashSet ,但是使用IEqualityComparer

所以,一起,你想要转换你的HashSet如下:

 var myNewHashSet = new HashSet(myOldHashSet, StringComparer.OrdinalIgnoreCase); 

如果你想离开原来的区分大小写的版本,你可以用linq来查询,不区分大小写:

 var contains = set.Any(a => a.Equals(item, StringComparison.InvariantCultureIgnoreCase));