Применить функцию ко всем элементам коллекции через 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(){}
}