Вызывать функцию для каждого значения в общей коллекции С#
У меня есть набор целых значений в коллекции List.
Я хочу вызвать функцию для каждого значения в коллекции, где один из аргументов функции является значением коллекции.
Без этого в цикле foreach... есть ли способ выполнить это с помощью выражения lambda/linq?
что-то вроде... myList.Where(p => myFunc(p.Value));
?
спасибо заранее,
-s
Ответы
Ответ 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));
Ответ 6
Вы можете использовать метод ForEach:
MSDN:
http://msdn.microsoft.com/en-us/library/bwabdf9z.aspx
Ответ 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);
}