如何将linq结果转换为HashSet或HashedSet

Jam*_*mie 186 c# linq

我有一个属于ISet的类的属性.我试图将linq查询的结果导入该属性,但无法弄清楚如何执行此操作.

基本上,寻找这个的最后部分:

ISet<T> foo = new HashedSet<T>();
foo = (from x in bar.Items select x).SOMETHING;
Run Code Online (Sandbox Code Playgroud)

也可以这样做:

HashSet<T> foo = new HashSet<T>();
foo = (from x in bar.Items select x).SOMETHING;
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 297

认为没有内置的东西可以做到这一点......但是编写扩展方法真的很容易:

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(
        this IEnumerable<T> source,
        IEqualityComparer<T> comparer = null)
    {
        return new HashSet<T>(source, comparer);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您确实需要扩展方法(或至少是某种形式的通用方法),因为您可能无法明确表达类型T:

var query = from i in Enumerable.Range(0, 10)
            select new { i, j = i + 1 };
var resultSet = query.ToHashSet();
Run Code Online (Sandbox Code Playgroud)

你不能通过显式调用HashSet<T>构造函数来做到这一点.我们依靠通用方法的类型推断来为我们做这件事.

现在你可以选择命名ToSet并返回ISet<T>- 但我坚持使用ToHashSet具体类型.这与标准LINQ运算符(ToDictionary,ToList)一致,并允许将来扩展(例如ToSortedSet).您可能还希望提供指定要使用的比较的重载.

  • @Joel:是的,他们这样做.否则各种各样的事情都会失败.不可否认,他们只使用组件类型的默认相等比较器,但这通常足够好. (4认同)
  • 匿名类型的好点.但是,匿名类型是否有"GetHashCode"和"Equals"的有用覆盖?如果没有,他们在HashSet中的表现不会太好...... (2认同)
  • @JonSkeet - 你知道为什么在标准LINQ运算符和ToDictionary和ToList之间没有提供这个?我听说为什么省略这些东西通常有很好的理由,类似于缺少的IEnumerable <T> .ForEach方法 (2认同)

Joe*_*ler 73

只需将您的IEnumerable传递给HashSet的构造函数即可.

HashSet<T> foo = new HashSet<T>(from x in bar.Items select x);
Run Code Online (Sandbox Code Playgroud)

  • @Jon,我认为这是YAGNI,直到另有证实. (6认同)
  • 您如何应对导致匿名类型的投影? (2认同)
  • @Rune FS:在这种情况下,我怀疑示例代码不现实.有一个类型参数T很少见,但知道`bar.Items`的每个项目都是`T`.考虑到实现这个通用目的是多么容易,以及LINQ中出现匿名类型的频率,我认为值得采取额外步骤. (2认同)

Dou*_*las 25

此功能已被添加作为扩展方法IEnumerable<TSource>的.NET Framework 4.7.2:

  • 还包含在[netcore 2.0及更高版本]中(https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.tohashset?view=netcore-3.0) (2认同)

Mat*_*ott 17

正如@Joel所说,你可以直接传递你的枚举.如果你想做一个扩展方法,你可以这样做:

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items)
{
    return new HashSet<T>(items);
}
Run Code Online (Sandbox Code Playgroud)