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
GetDistinctValuesUsingForEac h No2:1,2,3,4
我不明白为什么我没有在“GetDistinctValuesUsingWhere No2”行中得到任何值。
任何人都可以解释这一点吗?
UPDATE从斯科特的回答后,我改变了例子如下:
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。
但是,如果我只是取消对该行
回报Where2(项目,capturedVariables);
和注释行
的foreach(VAR i的项) 如果(capturedVariables.set.Add(i))的产量 返回I;
在GetDistinctValuesUsingWhere2方法中,我只会得到输出1,2,3,4一次。这很简单,删除的行和现在未注释的方法完全相同。
我还是不明白....
题外话,为什么不直接使用'Distinct'(或者用于具有属性的对象,MoreLINQ的'DistinctBy')而不是滚动自己的?或者这仅仅是一个学习练习? –
尝试在你的末尾添加'.ToList()',你应该得到正确的结果。问题在于您要返回表达式,所以每次请求对象时都会重新评估它。 – Kolichikov
可能的重复:[如何判断一个IEnumerable是否需要延迟执行?](https://stackoverflow.com/questions/1168944/how-to-tell-if-an-ienumerablet-is-subject-to-推迟执行) –
Igor