1

我有这个功能来重复一个序列:

public static List<T> Repeat<T>(this IEnumerable<T> lst, int count)
{
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}

现在,如果我这样做:

var d = Enumerable.Range(1, 100);
var f = d.Select(t => new Person()).Repeat(10); 
int i = f.Distinct().Count();

我希望i是 100,但它给了我 1000!我的问题严格来说是为什么会发生这种情况?Linq 不应该足够聪明地找出我需要与 variable 连接的第一个选定的 100 人ret吗?我有一种感觉,当它与 a 一起使用时,它在..执行时Concat被优先考虑。Selectret.ToList()

编辑:

如果我这样做,我会得到预期的正确结果:

var f = d.Select(t => new Person()).ToList().Repeat(10); 
int i = f.Distinct().Count(); //prints 100

再次编辑:

我没有覆盖Equals. 我只是想获得 100 个独特的人(当然是通过参考)。我的问题是有人可以向我解释为什么 Linq 不先进行选择操作然后进行连接(当然是在执行时)?

4

3 回答 3

4

问题是,除非您调用ToList,否则d.Select(t => new Person())每次遍历列表时都会重新枚举Repeat,从而创建重复Person的 s。该技术被称为延迟执行

一般来说,LINQ不会假设每次枚举一个序列时都会得到相同的序列,甚至是相同长度的序列。如果这种效果不理想,您总是可以Repeat通过立即调用在您的方法中“实现”序列ToList,如下所示:

public static List<T> Repeat<T>(this IEnumerable<T> lstEnum, int count) {
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var lst = lstEnum.ToList(); // Enumerate only once
    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}
于 2012-11-21T19:33:44.723 回答
1

我可以将我的问题分解为不那么琐碎的事情:

var d = Enumerable.Range(1, 100);
var f = d.Select(t => new Person());

现在基本上我正在这样做:

f = f.Concat(f);

请注意,查询到现在还没有执行。在执行时f仍然d.Select(t => new Person()) 未执行。所以执行时的最后一条语句可以分解为:

f = f.Concat(f); 
//which is 
f = d.Select(t => new Person()).Concat(d.Select(t => new Person()));

这显然会创建 100 + 100 = 200 个新的人员实例。所以

f.Distinct().ToList(); //yields 200, not 100

这是正确的行为。

编辑:我可以简单地重写扩展方法,

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}

我使用 dasblinkenlight 的建议来解决这个问题。

于 2012-11-21T21:32:06.130 回答
0

每个Person对象都是一个单独的对象。所有 1000 个都是不同的。

类型相等的定义是什么Person?如果您不覆盖它,该定义将是引用相等,这意味着所有 1000 个对象都是不同的。

于 2012-11-21T19:32:16.477 回答