使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));