【问题标题】:How to convert a for (not foreach) loop to Linq?如何将 for(不是 foreach)循环转换为 Linq?
【发布时间】:2013-12-24 14:01:44
【问题描述】:

假设我想要一个由 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 的分布中获取样本序列。原则上,我可以编写自己的方法来以相同的方式生成迭代器,但我想知道是否已经存在一个。

【问题讨论】:

  • 我在这里可能真的不合时宜,但恕我直言,LINQ 的目的是减少代码行数并根据某些条件从可枚举中选择某些元素。它并不是真的打算创建新对象。
  • 不,这是一个完全合理的评论。然而,对我来说,在某些情况下,LINQ 更容易阅读(在我自己的个人项目中)。

标签: c# linq for-loop


【解决方案1】:

您可以尝试使用 foreach 方法:

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

恕我直言,你必须在两者之间做一个 ToList。

edit 误读问题,所以 nvmd :)

【讨论】:

  • 实际上我的意思是foreach 循环,而不是Foreach 方法。你的代码几乎就是我想要的......但为什么我需要调用ToList
  • @Superbest 因为扩展方法Foreach 是在List&lt;T&gt; 上定义的,而不是IEnumerable&lt;T&gt;
  • @Vache ForEach 既不是扩展方法也不是 LINQ 方法,尽管许多人相信。这是一个可以追溯到 .NET 2.0 的 List&lt;T&gt; 方法。
  • @MatthewFerreira 确实!感谢您的更正,我会记住这一点。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    我不认为像你的 Enumerable.ObjectMaker 这样的东西作为 LINQ 的一个方便的部分存在,但你可以制作一个完全一样的东西。

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

    【讨论】:

      【解决方案4】:

      我同意丹麦语:我认为尝试在 base 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);
      

      【讨论】:

        【解决方案5】:

        我们可以创建一个新方法来生成 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);
        

        【讨论】:

          猜你喜欢
          • 2014-03-16
          • 2018-01-19
          • 1970-01-01
          • 1970-01-01
          • 2021-03-12
          • 1970-01-01
          • 1970-01-01
          • 2019-05-10
          • 1970-01-01
          相关资源
          最近更新 更多