Подтвердить что ты не робот

Вызывать функцию для каждого значения в общей коллекции С#

У меня есть набор целых значений в коллекции List. Я хочу вызвать функцию для каждого значения в коллекции, где один из аргументов функции является значением коллекции. Без этого в цикле foreach... есть ли способ выполнить это с помощью выражения lambda/linq?

что-то вроде... myList.Where(p => myFunc(p.Value));?

спасибо заранее, -s

4b9b3361

Ответ 1

LINQ здесь не помогает, но вы можете использовать List<T>.ForEach:

List <T> .ForEach Method

Выполняет указанное действие для каждого элемента списка.

Пример:

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

Значение, переданное в выражение лямбда, является элементом списка, поэтому в этом примере p является long, если myList является List<long>.

Ответ 2

Как отмечали другие плакаты, вы можете использовать List<T>.ForEach.

Однако вы можете легко написать метод расширения, который позволяет использовать ForEach на любом IEnumerable<T>

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<>, которое не предоставляет никакого типа возврата.

В любом случае есть ответ за то, что вы хотели, вы можете сделать это так же, как вы догадались с помощью Func<>, но с крошечным трюком, как показано ниже:

Я сделаю все здесь на лету:

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<string> будет объявлен для каждого элемента данного массива, так как он называется x.. p >

(Посмотрите на пустую скобку и помните, что когда вы определяете Func<type**1**, type**2**, ..., type**n**>, всегда последний тип - это тип возвращаемого значения, поэтому, когда вы пишете только Func<string>, это указывает на функцию, у которой нет входного параметра, а его тип возврата - строка)

Понятно, что мы хотим использовать функцию над данным массивом (new string[] { "d", "f" }), и поэтому я определяю функцию без параметра, а также я использовал ту же переменную x внутри Func<>, чтобы ссылаться на те же элементы массива.

Третий. Если вы не поместили второй 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>();

Наконец, я преобразовал результат в массив! Теперь у вас есть строковый массив!

Извините! Надеюсь, это было бы полезно.

Ответ 4

Вы можете использовать метод List.ForEach, как таковой:

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

Ответ 5

Нет - если вы хотите вызвать функцию для каждого элемента в списке, вы должны вызвать функцию для каждого элемента в списке.

Однако вы можете использовать метод IList<T>.ForEach() как немного синтаксического сахара, чтобы сделать "бизнес-конец" кода более удобочитаемым, например:

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

Ответ 7

Если вы не хотите использовать метод ForEach в List<T>, а скорее используете IEnumerable<T> (как это часто бывает при "LINQ: ing"), я предлагаю MoreLINQ, написанный Jon Skeet, et al.

MoreLINQ предоставит вам ForEach, а также Pipe (и кучу других методов), который выполняет действие для каждого элемента, но возвращает тот же IEnumerable<T> (по сравнению с 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 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);
}