【发布时间】:2017-08-25 18:29:21
【问题描述】:
这段代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication
{
internal class Program
{
public static void Main()
{
var values = new[] {1, 2, 3, 3, 2, 1, 4};
var distinctValues = GetDistinctValuesUsingWhere(values);
Console.WriteLine("GetDistinctValuesUsingWhere No1: " + string.Join(",", distinctValues));
Console.WriteLine("GetDistinctValuesUsingWhere No2: " + string.Join(",", distinctValues));
distinctValues = GetDistinctValuesUsingForEach(values);
Console.WriteLine("GetDistinctValuesUsingForEach No1: " + string.Join(",", distinctValues));
Console.WriteLine("GetDistinctValuesUsingForEach No2: " + string.Join(",", distinctValues));
Console.ReadLine();
}
private static IEnumerable<T> GetDistinctValuesUsingWhere<T>(IEnumerable<T> items)
{
var set=new HashSet<T>();
return items.Where(i=> set.Add(i));
}
private static IEnumerable<T> GetDistinctValuesUsingForEach<T>(IEnumerable<T> items)
{
var set=new HashSet<T>();
foreach (var i in items)
{
if (set.Add(i))
yield return i;
}
}
}
}
产生以下输出:
GetDistinctValuesUsingWhere No1: 1,2,3,4
GetDistinctValuesUsingWhere No2:
GetDistinctValuesUsingForEach No1: 1,2,3,4
GetDistinctValuesUsingForEach No2: 1,2,3,4
我不明白为什么在“GetDistinctValuesUsingWhere No2”行中没有得到任何值。
谁能给我解释一下?
更新在 Scott 回答后,我将示例更改为以下内容:
private static IEnumerable<T> GetDistinctValuesUsingWhere2<T>(IEnumerable<T> items)
{
var set = new HashSet<T>();
var capturedVariables = new CapturedVariables<T> {set = set};
foreach (var i in items)
if (capturedVariables.set.Add(i))
yield return i;
//return Where2(items, capturedVariables);
}
private static IEnumerable<T> Where2<T>(IEnumerable<T> source, CapturedVariables<T> variables)
{
foreach (var i in source)
if (variables.set.Add(i))
yield return i;
}
private class CapturedVariables<T>
{
public HashSet<T> set;
}
这将导致输出 1、2、3、4 的两倍。
但是,如果我只是取消注释该行
return Where2(items, captureVariables);
并注释行
foreach(项目中的变量 i) if (capturedVariables.set.Add(i)) 收益回报 i;
在GetDistinctValuesUsingWhere2方法中,我只会得到一次输出1,2,3,4。这尽管删除的行和现在未注释的方法完全相同。
我还是不明白....
【问题讨论】:
-
离题,但为什么不直接使用
Distinct(或者对于具有属性的对象,MoreLINQ 的DistinctBy)而不是自己滚动?或者这仅仅是一个学习练习? -
尝试在 Where 末尾添加
.ToList(),您应该会得到正确的结果。问题是您正在返回表达式,因此每次请求对象时都会重新评估它。 -
当然我会在现实生活中使用 Distinct。这只是我们最近偶然发现的一个更复杂问题的简化示例。
-
重新编辑:您熟悉closures 的概念吗?