C# 使 HashSet<string> 不区分大小写

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16922435/
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-10 08:07:57  来源:igfitidea点击:

Make HashSet<string> case-insensitive

c#.nethashset

提问by wishmaster

I have method with HashSet parameter. And I need to do case-insensitive Contains within it:

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

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

Is it any way to make existing HashSet case-insensitive (do not create new one)?

有什么方法可以使现有的 HashSet 不区分大小写(不要创建新的)?

I'm looking for solution with best perfomance.

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

Edit

编辑

Contains can be called multiple times. So IEnumerable extensions are not acceptable for me due to lower perfomance than native HashSet Contains method.

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

Solution

解决方案

Since, answer to my question is NO, it is impossible, I've created and used following method:

因为,我的问题的答案是否定的,这是不可能的,我创建并使用了以下方法:

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

采纳答案by Timothy Shields

The HashSet<T>constructor has an overload that lets you pass in a custom IEqualityComparer<string>. There are a few of these defined for you already in the static StringComparerclass, a few of which ignore case. For example:

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

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

You'll have to make this change at the time of constructing the HashSet<T>. Once one exists, you can't change the IEqualityComparer<T>it's using.

您必须在构建HashSet<T>. 一旦存在,您就无法更改IEqualityComparer<T>它正在使用的内容。



Just so you know, by default (if you don't pass in any IEqualityComparer<T>to the HashSet<T>constructor), it uses EqualityComparer<T>.Defaultinstead.

正如您所知,默认情况下(如果您没有将任何内容传递IEqualityComparer<T>HashSet<T>构造函数),它会EqualityComparer<T>.Default改为使用。



Edit

编辑

The question appears to have changed after I posted my answer. If you have to do a case insensitivesearch in an existing case sensitiveHashSet<string>, you will have to do a linear search:

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

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

There's no way around this.

没有办法解决这个问题。

回答by It'sNotALie.

Assuming you've got this extension method:

假设你有这个扩展方法:

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

You can just use this:

你可以使用这个:

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

Or, you could just do this:

或者,你可以这样做:

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

回答by eouw0o83hf

If you want to leave the original, case-sensitive version in place, you could just query it with linq with case insensitivity:

如果您想保留原始的、区分大小写的版本,您可以使用不区分大小写的 linq 查询它:

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

回答by Ben Reich

The constructor of HashSetcan take an alternative IEqualityComparerthat can override how equality is determined. See the list of constructors here.

的构造函数HashSet可以采用替代方法IEqualityComparer,该替代方法可以覆盖确定相等性的方式。请参阅此处的构造函数列表。

The class StringComparercontains a bunch of static instances of IEqualityComparersfor strings. Particularly, you're probably interested in StringComparer.OrdinalIgnoreCase. Hereis the documentation of StringComparer.

该类StringComparer包含一堆IEqualityComparersfor 字符串的静态实例。特别是,您可能对StringComparer.OrdinalIgnoreCase. 是 的文档StringComparer

Note that another constructor takes in an IEnumerable, so you can construct a new HashSetfrom your old one, but with the IEqualityComparer.

请注意,另一个构造函数接受IEnumerable,因此您可以HashSet从旧构造函数构造一个新构造函数,但使用IEqualityComparer.

So, all together, you want to convert your HashSetas follows:

因此,总而言之,您希望HashSet按如下方式转换:

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

回答by Alexei Levenkov

You can not magically make case-sensetive HashSet (or Dictionary) to behave in case-insensitive way.

你不能神奇地让区分大小写的 HashSet(或字典)以不区分大小写的方式表现。

You have to recreate one inside your function if you can not rely on incoming HashSetto be case-insensitive.

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

Most compact code - use constructorfrom existing set:

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

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

Note that copying HashSetis as expensive as walking through all items, so if your function does just on search it would be cheaper (O(n)) to iterate through all items. If your function called multiple times to make single case-insensitive search you should try to pass proper HashSetto it instead.

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

回答by Miserable Variable

The HashSetis designed to quickly find elements as per its hashing function and equality comparator. What you are asking for is really to find an element matching "some other" condition. Imagine that you have a Set<Person>objects that uses only Person.Namefor comparison and you need to find an element with some given value of Person.Age.

HashSet设计为快速查找元素按其散列函数和平等比较。您所要求的实际上是找到一个与“其他”条件匹配的元素。想象一下,您有一个Set<Person>Person.Name用于比较的对象,并且您需要找到具有某个给定值为 的元素Person.Age

The point is you need to iterate over the contents of the set to find the matching elements. If you are going to be doing this often you might create a different Set, in you case using a case-insensitive comparator but then you would have to make sure that this shadow set is in sync with the original.

关键是您需要遍历集合的内容以找到匹配的元素。如果您要经常这样做,您可能会创建一个不同的 Set,在您的情况下使用不区分大小写的比较器,但您必须确保此阴影集与原始集同步。

The answers so far are essentially variations of the above, I thought to add this to clarify the fundamental issue.

到目前为止的答案基本上是上述的变体,我想添加这个来澄清基本问题。

回答by Elanis

You can now use

您现在可以使用

set.Contains(item, StringComparer.OrdinalIgnoreCase);

without needing to re-create you HashSet

无需重新创建 HashSet