如何将for(不是foreach)循环转换为Linq?

时间:2013-12-24 14:01:45

标签: c# linq for-loop

假设我想要一个包含10个数字的序列,并且我有一个按需生成数字的函数:

var s = new List<int>();
for (var i=0; i<10; i++) {
    s.Add(Magically_generate_a_very_special_number());
}

通常是实现这一目标的方法。但是,假设我想使用LINQ。我已经可以做了(让我们忽略类型之间的区别):

var s = Enumerable.Range(0, 10).Select(i => MathNet.Numerics.Statistics.DescriptiveStatistics())

这对我来说几乎已经足够了。然而,令我困扰的是我需要首先指定一系列整数 - 这是一个多余的步骤,因为我无论如何都要丢弃这个值。是否有可能做以下事情?

var s = Enumerable.ObjectMaker(Magically_generate_a_very_special_number).Take(10);

似乎Enumerable.Repeat几乎做了我想要的,但是它接受我给它的函数的结果,然后重复它,而不是重复评估函数。

顺便提一下,这个问题的灵感来自于Math.Net IContinuousDistribution.Samples方法。它的身体如下:

while (true)
{
    yield return Generate_a_random_number();
}

这样您就可以使用myDistribution.Samples.Take从分布中获取一系列样本。原则上,我可以用同样的方式编写自己的方法来生成迭代器,但我想知道是否有一个已经存在的迭代器。

5 个答案:

答案 0 :(得分:2)

您可以尝试使用foreach方法:

Enumerable.Take(10).ToList().Foreach(Magically_generate_a_very_special_number);

Downnside imho是你必须在两者之间做一个ToList。

编辑误读问题,所以nvmd:)

答案 1 :(得分:1)

您可以创建一个引用您的Magically_generate_a_very_special_number方法的10个方法委托的序列,然后连续调用它们。

var s = Enumerable.Repeat<Func<int>>(generate, 10).Select(f => f());

答案 2 :(得分:1)

我认为你的Enumerable.ObjectMaker之类的东西不是LINQ的一个方便部分,但是你可以使它完全像它一样。

public static IEnumerable<T> ObjectMaker<T>(Func<T> generator) {
    while (true)
        yield return generator();
}
var s = ObjectMaker(MagicallyGenerateVerySpecialNumber).Take(10);

答案 3 :(得分:0)

我同意丹麦语:我认为尝试在基础linq中进行操作比在for循环中执行它更难以阅读。似乎打败了linq的目的。

那就是说,也许你可以做一个扩展方法。只要你的Magically_generate_a_very_special_number函数不需要参数,像这样的东西应该做你想要的:

public static void Fill<T>(this IList<T> list, int repeat, Func<T> fn) {
    for (int i = 0; i < repeat; i++) list.Add(fn());
}

然后像这样使用:

s.Fill(10, Magically_generate_a_very_special_number);

答案 4 :(得分:0)

我们可以创建一个新方法来生成N个对象,方法是调用生成函数N次,遵循LINQ方法的一般模式,这样就可以满足您的确切需求:

public static IEnumerable<T> Generate<T>(Func<T> generator, int count)
{
    for (int i = 0; i < count; i++)
        yield return generator();
}

现在你可以写:

var numbers = Generate(Magically_generate_a_very_special_number, 10);