简体   繁体   English

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

[英]How to convert a for (not foreach) loop to Linq?

Let's say I want a sequence of 10 numbers, and I have a function which produces numbers on demand: 假设我想要一个由10个数字组成的序列,并且我有一个按需产生数字的函数:

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

Is the usual way of accomplishing this. 是完成此操作的常用方法。 However, let's say I want to use LINQ. 但是,假设我要使用LINQ。 I can already do (let's ignore the distinction between types): 我已经可以了(让我们忽略类型之间的区别):

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

Which is almost good enough for me. 这对我几乎足够了。 However, it bothers me that I need to specify a range of integers first - this is a superfluous step since I discard the value anyway. 但是,令我困扰的是我需要首先指定整数范围-这是多余的步骤,因为无论如何我都放弃了该值。 Is it possible to do something like the following? 是否可以执行以下操作?

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

It seems that Enumerable.Repeat almost does what I want, but it takes the result of the function I give it and then duplicates that, instead of repeatedly evaluating the function. 似乎Enumerable.Repeat几乎可以完成我想要的操作,但是它采用了我给它的函数结果,然后对其进行了复制,而不是反复评估该函数。

By the way, the inspiration for this question was the Math.Net IContinuousDistribution.Samples method. 顺便说一句,此问题的灵感来自Math.Net IContinuousDistribution.Samples方法。 Its body looks like the following: 它的主体如下所示:

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

So that you can obtain a sequence of samples from the distribution with myDistribution.Samples.Take . 这样您就可以使用myDistribution.Samples.Take从分布中获取样本序列。 In principle, I could just write my own method to produce an iterator in the same way, but I'm wondering if there is one that already exists. 原则上,我可以编写自己的方法以相同的方式生成迭代器,但是我想知道是否已经存在一个迭代器。

You could try using the foreach method : 您可以尝试使用foreach方法:

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

Downside imho is that you have to do a ToList in between. 缺点恕我直言,您必须在两者之间执行ToList。

edit misread question, so nvmd :) 编辑误读的问题,所以nvmd :)

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

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

I don't think anything like your Enumerable.ObjectMaker exists as a convenient part of LINQ, but you can make one exactly like it. 我不认为像Enumerable.ObjectMaker这样的东西可以作为LINQ的便捷部分存在,但是您可以完全像它一样制作一个。

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

I agree with danish: I think trying to do it in base linq is uglier and harder to read than just doing it in a for loop. 我同意丹麦语:我认为尝试在基本linq中进行操作比仅在for循环中进行操作更丑陋且更难以阅读。 Seems to defeat the purpose of linq. 似乎打败了linq的目的。

That said, maybe you can make an extension method. 也就是说,也许您可​​以制作一个扩展方法。 So long as your Magically_generate_a_very_special_number function doesn't require parameters, something like this should do what you're after: 只要您的Magically_generate_a_very_special_number函数不需要参数,类似的事情就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());
}

Then use like this: 然后像这样使用:

s.Fill(10, Magically_generate_a_very_special_number);

We can create a new method to generate N objects by calling a generation function N times that follows the general pattern of LINQ methods, so that you have something that fits your exact needs: 我们可以通过按照LINQ方法的一般模式调用N次生成函数来创建一个新的方法来生成N个对象,这样您就可以满足您的确切需求:

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

And now you can write: 现在您可以编写:

var numbers = Generate(Magically_generate_a_very_special_number, 10);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM