【问题标题】:call a function for each value in a generic c# collection [duplicate]为通用 c# 集合中的每个值调用一个函数[重复]
【发布时间】:2010-12-25 10:20:00
【问题描述】:

我在 List 集合中有一组整数值。 我想为集合中的每个值调用一个函数,其中函数的参数之一是集合值。 如果不在 foreach 循环中执行此操作...有没有办法使用 lambda/linq 表达式来完成此操作?

类似... myList.Where(p => myFunc(p.Value)); ?

提前致谢, -s

【问题讨论】:

  • 你需要函数产生的值还是运行函数的副作用?
  • 您拒绝 foreach 循环解决方案有什么原因吗?我说一个声明应该有副作用。如果您想对序列的每个成员调用副作用函数,那么专门设计用于执行此操作的语句——foreach 语句——似乎是自然的选择。你能解释一下为什么你拒绝为你想要的而设计的语言功能吗?
  • @Eric 没错,我正要发布那个。我一直不明白为什么有人会使用List<T>.ForEach 而不是foreach。善用 Linq 可以混淆很多复杂的、嵌套的代码;但是,有时人们似乎喜欢 lambda 表达式的外观。

标签: c# linq lambda generics


【解决方案1】:

LINQ 在这里没有帮助,但你可以使用 List<T>.ForEach:

List.ForEach 方法

对列表的每个元素执行指定的操作。

例子:

myList.ForEach(p => myFunc(p));

传递给 lambda 表达式的值是列表项,因此在此示例中,如果 myListList<long>,则 plong

【讨论】:

  • 谢谢——这正是我一直在寻找的东西,可能在某个地方看到过,但不记得了......
  • 或者,如果 myFunc 与预期的 ForEach 委托的签名匹配,您可以指定 myList.ForEach(myFunc)
【解决方案2】:

正如其他海报所指出的,您可以使用List<T>.ForEach

但是,您可以轻松编写一个扩展方法,允许您在任何 IEnumerable<T> 上使用 ForEach

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach(T item in source)
        action(item);
}

这意味着你现在可以这样做:

myList.Where( ... ).ForEach( ... );

【讨论】:

    【解决方案3】:

    耶!您可以使用List.ForEach,但问题是它仅适用于列表(当然您可以随时将所有内容更改为列表,但更少的代码更有趣:))。此外,您必须使用不提供任何返回类型的Action&lt;&gt; 预测。

    无论如何,您想要的答案都有,您可以用Func&lt;&gt; 猜测的相同方式使其成为可能,但有一个小技巧如下:

    我会在这里做所有事情:

    string[] items = (new string[] { "d", "f" }).
        Select(x => new Func<string>(() => { 
            //Do something here...
            Console.WriteLine(x); 
            return x.ToUpper(); 
        }
    )).Select(t => t.Invoke()).ToArray<string>();
    

    这里有几点:

    首先,我已经动态定义了一个字符串数组,它可以被任何支持 LINQ 的集合替换。

    第二,在Select 内部,将为给定数组的每个元素声明一个Func&lt;string&gt;,因为它称为x。。 p>

    (看看空括号,记住当你定义一个Func&lt;type**1**, type**2**, ..., type**n**&gt;时,最后一个类型总是返回类型,所以当你只写Func&lt;string&gt;时,它表示一个没有输入参数的函数及其返回类型是字符串)

    很明显,我们想在给定数组(new string[] { "d", "f" }) 上使用函数,这就是为什么我定义了一个没有参数的函数,而且我在Func&lt;&gt; 内部使用了相同的变量x 来引用相同的数组元素。

    第三,如果您不放置 second Select,那么您将拥有两个返回字符串的函数的集合,并且它们已经从第一个数组。您可以这样做并将结果保存在anonymous 变量中,然后调用他们的.Invoke 方法。我写在这里:

    var functions = (new string[] { "d", "f" }).
           Select(x => new Func<string>(() => { 
              //Do something here...
              Console.WriteLine(x); 
              return x.ToUpper(); 
           }));
    string[] items = functions.Select(t => t.Invoke()).ToArray<string>();
    

    最后,我将结果转换为数组!现在你有了一个字符串数组!

    对不起,它变长了!!希望对你有用。

    【讨论】:

    • 既然我们已经在使用 linq,为什么不在 .ForEach() 前面加上 .ToList() 呢? IEnumerable&lt;T&gt;.ToList&lt;T&gt; 返回一个 IList&lt;T&gt;
    【解决方案4】:

    您可以使用 List.ForEach 方法,如下所示:

    myList.ForEach(p => myFunc(p));
    

    【讨论】:

      【解决方案5】:

      否 - 如果您想为列表中的每个项目调用一个函数,您必须为列表中的每个项目调用该函数。

      但是,您可以将IList&lt;T&gt;.ForEach() 方法用作一点语法糖,以使代码的“业务端”更具可读性,如下所示:

      items.ForEach(item => DoSomething(item));
      

      【讨论】:

        【解决方案6】:

        您可以使用 ForEach 方法:

        MSDN:

        http://msdn.microsoft.com/en-us/library/bwabdf9z.aspx

        【讨论】:

          【解决方案7】:

          如果你不想使用List&lt;T&gt; 的ForEach 方法,而是使用IEnumerable&lt;T&gt;(就像“LINQ:ing”时经常使用的那样),我建议使用Jon Skeet 编写的MoreLINQ,等。

          MoreLINQ 将为您提供 ForEach 和 Pipe(以及许多其他方法),它们对每个元素执行一个操作,但返回相同的 IEnumerable&lt;T&gt;(与 void 相比)。

          【讨论】:

            【解决方案8】:

            这是一个迷你(但完整的)示例。

            public class Employee
            {
                public string EmployeeNumber { get; set; }
                public DateTime? HireDate { get; set; }
            }
            public class EmployeeCollection : List<Employee>
            { }
            
            private void RunTest()
            {
                EmployeeCollection empcoll = new EmployeeCollection();
                empcoll.Add(new Employee() { EmployeeNumber = "1111", HireDate = DateTime.Now });
                empcoll.Add(new Employee() { EmployeeNumber = "3333", HireDate = DateTime.Now });
                empcoll.Add(new Employee() { EmployeeNumber = "2222", HireDate = null });
                empcoll.Add(new Employee() { EmployeeNumber = "4444", HireDate = null });
            
                //Here's the "money" line!
                empcoll.Where(x => x.HireDate.HasValue == false).ToList().ForEach(item => ReportEmployeeWithMissingHireDate(item.EmployeeNumber));
            
            }
            private void ReportEmployeeWithMissingHireDate(string employeeNumber)
            {
                Console.WriteLine("We need to find a HireDate for '{0}'!", employeeNumber);
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-07-25
              • 2017-03-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-03-06
              • 1970-01-01
              • 2016-04-02
              相关资源
              最近更新 更多