使HashSet <string>不区分大小写

wis*_*ter 62 .net c# hashset

我有HashSet参数的方法.我需要在其中做不区分大小写的包含:

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

是否可以使现有的HashSet不区分大小写(不创建新的)?

我正在寻找具有最佳性能的解决方案.

编辑

包含可以多次调用.因此,由于性能低于本机HashSet Contains方法,IEnumerable扩展对我来说是不可接受的.

既然,回答我的问题是NO,那是不可能的,我已经创建并使用了以下方法:

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

Tim*_*lds 109

HashSet<T>构造具有过载,可以让你在一个自定义的传递IEqualityComparer<string>.在静态StringComparer类中已经为您定义了一些这些,其中一些忽略了大小写.例如:

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

你必须在构建时做出这个改变HashSet<T>.一旦存在,您就无法更改IEqualityComparer<T>它的使用.


只要你知道,在默认情况下(如果你不以任何传递IEqualityComparer<T>HashSet<T>构造函数),它使用EqualityComparer<T>.Default来代替.


编辑

在我发布答案后,问题似乎已经改变了.如果你必须做的情况下,不区分大小写在现有的情况下,搜索敏感 HashSet<string>,你将不得不做线性搜索:

set.Any(s => string.Equals(s, item, StringComparison.OrdinalIgnoreCase));
Run Code Online (Sandbox Code Playgroud)

没有办法解决这个问题.

  • @DaveBish这正是我编辑我的答案以包含LINQ线性扫描的原因.:) (3认同)
  • 这是一个替代方案,但我更喜欢**上面更清晰的 LINQ 解决方案**。您可以使用“Enumerable.Contains&lt;TSource&gt;(this IEnumerable&lt;TSource&gt; source, TSource value, IEqualityComparer&lt;TSource&gt; Comparer)”,如下所示:“set.Contains(item, StringComparison.OrdinalIgnoreCase)”。它通常会执行相同的线性搜索,但 Resharper 会生成“集合中可能出现意外的线性搜索”警告。 (2认同)

Ale*_*kov 6

你不能神奇地使区分大小写的HashSet(或Dictionary)以不区分大小写的方式运行.

如果您不能依赖传入HashSet不区分大小写,则必须在函数内重新创建一个.

最紧凑的代码 - 使用现有集合中的构造函数:

var insensitive = new HashSet<string>(
   set, StringComparer.InvariantCultureIgnoreCase);
Run Code Online (Sandbox Code Playgroud)

请注意,复制HashSet与遍历所有项目一样昂贵,因此如果您的函数仅在搜索时执行,则迭代所有项目会更便宜(O(n)).如果您的函数多次调用以进行单个不区分大小写的搜索,则应尝试将其正确传递HashSet给它.