Применить функцию ко всем элементам коллекции через LINQ
Недавно я начал работать с LINQ и его потрясающим. Мне было интересно, сможет ли LINQ позволить мне применить функцию - любую функцию - ко всем элементам коллекции, не используя foreach. Что-то вроде функций лямбда-питона.
Например, если у меня есть список int, могу ли я добавить константу для каждого элемента, используя LINQ
Если у меня есть таблица БД, могу ли я установить поле для всех записей с помощью LINQ.
Я использую С#
Ответы
Ответ 1
Общим способом подхода к этому является добавление собственного ForEach
универсального метода на IEnumerable<T>
. Здесь у нас есть MoreLINQ:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
source.ThrowIfNull("source");
action.ThrowIfNull("action");
foreach (T element in source)
{
action(element);
}
}
(Где ThrowIfNull
- метод расширения для любого ссылочного типа, что делает очевидную вещь.)
Будет интересно узнать, является ли это частью .NET 4.0. Это противоречит функциональному стилю LINQ, но нет сомнений в том, что многие люди считают это полезным.
Как только вы получите это, вы можете писать такие вещи, как:
people.Where(person => person.Age < 21)
.ForEach(person => person.EjectFromBar());
Ответ 2
Идиоматический способ сделать это с помощью LINQ - обработать коллекцию и вернуть новую коллекцию, отображаемую по вашему желанию. Например, чтобы добавить константу к каждому элементу, вам нужно что-то вроде
var newNumbers = oldNumbers.Select(i => i + 8);
Выполнение этого функциональным способом вместо изменения состояния вашей существующей коллекции часто помогает вам разделить отдельные операции таким образом, чтобы как легче читать, так и проще компилятору рассуждать.
Если вы находитесь в ситуации, когда вы действительно хотите применить действие к каждому элементу коллекции (действие с побочными эффектами, которые не связаны с фактическим содержимым коллекции), что на самом деле не то, что LINQ лучше всего подходит для, хотя вы можете подделать его с помощью Select
(или написать свой собственный метод расширения IEnumerable
, как и многие люди). В этом случае лучше всего придерживаться цикла foreach
.
Ответ 3
Вы также можете подумать о параллельности, особенно если вам не нужна последовательность и больше о том, как сделать что-то для каждого элемента:
SomeIEnumerable<T>.AsParallel().ForAll( Action<T> / Delegate / Lambda )
Например:
var numbers = new[] { 1, 2, 3, 4, 5 };
numbers.AsParallel().ForAll( Console.WriteLine );
НТН.
Ответ 4
Ха-ха, парень, я просто задал этот вопрос несколько часов назад (вроде)... попробуйте следующее:
Пример:
someIntList.ForEach(i=>i+5);
ForEach()
является одним из встроенных методов .NET
Это изменит список, а не возвращает новый.
Ответ 5
Или вы можете взломать его.
Items.All(p => { p.IsAwesome = true; return true; });
Ответ 6
Для коллекций, которые не поддерживают ForEach
, вы можете использовать статический метод ForEach
в классе Parallel
:
var options = new ParallelOptions() { MaxDegreeOfParallelism = 1 };
Parallel.ForEach(_your_collection_, options, x => x._Your_Method_());
Ответ 7
Вы можете попробовать что-то вроде
var foo = (from fooItems in context.footable select fooItems.fooID + 1);
Возвращает список id +1, вы можете сделать то же самое с использованием функции в том, что у вас есть в предложении select.
Обновление: как предложил Jon Skeet, это лучшая версия фрагмента кода, который я только что опубликовал:
var foo = context.footable.Select(foo => foo.fooID + 1);
Ответ 8
Я нашел какой-то способ для работы в словаре, содержащий мои собственные методы класса
foreach (var item in this.Values.Where(p => p.IsActive == false))
item.Refresh();
Где 'this', полученный из словаря < string, MyCustomClass >
class MyCustomClass
{
public void Refresh(){}
}