625

Is there a way to do the following using LINQ?

foreach (var c in collection)
{
    c.PropertyToSet = value;
}

To clarify, I want to iterate through each object in a collection and then update a property on each object.

My use case is I have a bunch of comments on a blog post, and I want to iterate through each comment on a blog post and set the datetime on the blog post to be +10 hours. I could do it in SQL, but I want to keep it in the business layer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lomaxx
  • 113,627
  • 57
  • 144
  • 179
  • 17
    Interesting question. Personally I prefer how you've got it above - far clearer what's going on! – noelicus Apr 25 '16 at 18:12
  • 12
    I came here looking for an answer to the same question, and decided that it was just as easy, less code, and easier to understand for future developers to just do it the way you did in you OP. – Casey Crookston Feb 02 '17 at 17:31
  • 4
    Why would you want to do it in LINQ? – Caltor Aug 17 '17 at 14:07
  • 18
    This question asks for the wrong thing, the only correct answer is: don't use LINQ to modify the datasource – Tim Schmelter Nov 16 '17 at 10:39
  • 4
    I'm voting to close this question as off-topic because almost all the answers to this question are actively harmful to new programmers' understanding of LINQ. – Tanveer Badar Mar 23 '20 at 14:07
  • @TimSchmelter there is something wrong in putting your comment as answer? Because is the answer, likely or not. – Leandro Bardelli Oct 09 '20 at 22:58
  • 4
    Wow, so many massively upvoted answers here that are just awful ways to do this. Just stick with a foreach loop, it's much more readable and has no weird side effects. – DavidG Jul 13 '21 at 16:39
  • `List.ForEach` isn't LINQ and using LINQ with side effects defies its very functional programming paradigm. So: no. – Gert Arnold Feb 04 '23 at 08:35

18 Answers18

993

While you can use a ForEach extension method, if you want to use just the framework you can do

collection.Select(c => {c.PropertyToSet = value; return c;}).ToList();

The ToList is needed in order to evaluate the select immediately due to lazy evaluation.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
Cameron MacFarland
  • 70,676
  • 20
  • 104
  • 133
  • 7
    I upvoted this because it's a pretty nice solution... the only reason I like the extension method is that it makes it a little clearer to understand exactly what is going on... however your solution is still pretty sweet – lomaxx Dec 30 '08 at 00:07
  • I agree, my answer is mainly for those who don't want to use the extension method. – Cameron MacFarland Dec 30 '08 at 04:48
  • 1
    If we are creating list anyway, can't we just type: collection.ToList().ForEach(c => c.PropertyToSet = value); – Karol Kolenda Feb 12 '10 at 09:53
  • 11
    If collection was an `ObservableCollection` say, then changing items in place rather than creating a new list can be useful. – Cameron MacFarland Mar 05 '10 at 22:44
  • 1
    +1 Helped me. Resharper is asking to remove .ToList() at the end. It says `Return value of pure method is not used.` – One-One Apr 25 '12 at 05:44
  • 10
    @desaivv yeah this is a bit of a syntax abuse, so Resharper is warning you about this. – Cameron MacFarland Apr 25 '12 at 07:07
  • 2
    I tried that but I keep on getting a compiler error: `A lambda expression with a statement body cannot be converted to an expression tree`. When I extracted it to a `Func`, it was fine again. Why's that? – Konrad Morawski Aug 23 '12 at 14:10
  • 5
    @KonradMorawski You're doing a select on an IQueryable not an IEnumerable, so most likely LINQ to SQL. This only works on LINQ to objects. – Cameron MacFarland Aug 23 '12 at 14:30
  • 1
    it was the `ToList()` that was missing... thanks you for the pointer! – nrod Feb 06 '13 at 20:06
  • What if we want to use a 'where' statement with that? – vaheeds May 19 '13 at 08:26
  • 65
    IMHO, this is far less expressive than a simple foreach loop. The ToList() is confusing because it is not used for anything but forcing evaluation that would otherwise be deferred. The projection is also confusing because it's not used for its intended purpose; rather, it's used to iterate over the elements of the collection and allow access to a property so that it can be updated. The only question in my mind would be whether or not the foreach loop could benefit from parallelism using Parallel.ForEach, but that's a different question. – Philippe Feb 10 '14 at 14:25
  • +1 for mentioning about lazy evaluation. It helped me. – Shrikey Jul 03 '14 at 07:15
  • Good one...This solution allows for fluid syntax (chaining functions). The ForEach extension does not. – toddmo Aug 21 '14 at 23:39
  • Is LINQ faster then foreach in this case? – rluks Sep 11 '15 at 07:45
  • 3
    @Pan.student hell no. To be honest I'm not sure I'd ever use this technique. – Cameron MacFarland Sep 11 '15 at 08:11
  • 1
    can anyone explain to me the inside code `return c;` please? – Shift 'n Tab May 31 '16 at 05:18
  • 3
    @ShiftN'Tab: Lambda expressions normally contain a single statement, eg `x => x.Id`. However, they are allowed to have multiple statements. In that case you need to use braces around the multiple statements. Also, if you need to return a value from a multi-statement lambda you have use a `return` statement. The example above includes a multi-statement lambda: `c => {c.PropertyToSet = value; return c;}`. It has 2 statements, which you would normally write on different lines for clarity: `c.PropertyToSet = value;` and `return c;` It's very like a C# 2.0 anonymous method. – Simon Elms Jun 24 '16 at 10:08
  • 7
    Can someone explain why is this the highest voted answer? Why is this better then using ForEach? – Igor Meszaros Nov 23 '16 at 14:15
  • @CameronMacFarland . what is the maning of "return c;"? is it requrired? cant we do it without "return c;" like in foreach example? – bh_earth0 Jan 12 '17 at 13:51
  • 4
    I am shocked this is the number 1 answer and has so many votes. This code would be an absolute nightmare to maintain. Why would you use a select when you could just use a ForEach?? Even the 2 line syntax of a for loop is easier to write and much more expressive of what the code is doing. For the love of God, please do not do this in your code!! – Edyn Sep 28 '18 at 15:42
  • 4
    This code mutates a collection while operating on it. `Select` should really be immutable and avoid side-effects like this. `ToList` also causes the allocation of another collection. Essentially, this code doesn't do what it appears to at first glance; anyone familiar with LINQ scanning this would not expect the collection to be modified. – aholmes Dec 26 '18 at 21:29
  • 3
    Consider https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/ – aholmes Dec 26 '18 at 21:40
  • 128
    **This answer is a worst practice. Never do this.** – Eric Lippert May 02 '19 at 17:09
  • 5
    @EricLippert can you clarify why this is not best practice, please? – MattVon Nov 05 '19 at 12:48
  • 18
    See all the other comments for reasons why this is a bad idea. You should never use a select to execute a side effect. The purpose of a select is to select a value, not to emulate a for each loop. – Eric Lippert Nov 05 '19 at 15:39
  • how can I use ternary operator for conditional assignment of value? `var test = dataSet.Select(f => { (some condition here)? f.Type = "Masked" : f.Type; return f; }).ToList();` – Kundan Nov 20 '19 at 19:13
  • @CodeRunner By posting this as a new question, not as a comment to an answer. Anyway, a ternary assumes both expressions can be evaluated to the exact same type. I doubt you need any for your task. Instead use a simple null-check and assign `f.Type = "Masked"` in this only case. – MakePeaceGreatAgain Feb 13 '20 at 11:57
  • That solution worked only if collection is already a list before applying the filters. If you try with a collection as IEnumerable , it will not work even if you add .ToList() at the end. – Zaibacker Aug 05 '20 at 09:02
  • In VS2017 I get a CS0832 and CS0834 compiler errors when doing it like this. – TK-421 Feb 17 '21 at 12:17
  • @EricLippert then what is best way to update a property from a list? – Imran Qadir Baksh - Baloch Jun 26 '21 at 15:54
  • 7
    @user960567: `foreach(var thing in stuff) thing.foo = bar;` is easily seen to be correct, is easy to read, is a best practice, and minimizes the amount extraneous allocations, none of which is true of the terrible practice described in this answer. – Eric Lippert Jun 29 '21 at 23:14
  • Can't it be simplified like this? collection.Select(c => c.PropertyToSet = value).ToList(); – Chandraprakash Sep 13 '21 at 07:45
  • not sure why everyone is hating on this answer but love the exact same code using .all – John Lord Sep 21 '21 at 14:53
  • 3
    **It would be nice if @Cameron would, at the very least, put a massive banner across the top of the answer saying what an awful idea it is and why it should never be done**. Cameron you clearly have the power to educate and, especially now your answer is a prominent google target, you have responsibility too.. You said in a tiny footnote in the comments that you'd never do what you're effectively advocating others do here; you really should tell people why because the comment stream is clearly full of people who cannot see why it's a bad idea and the answer contains disuasion at all – Caius Jard Mar 02 '22 at 11:24
  • Is there a way to do this with complex Lnq queries, such as using multiple joins? – AtomicallyBeyond Nov 25 '22 at 21:40
454
collection.ToList().ForEach(c => c.PropertyToSet = value);
Ε Г И І И О
  • 11,199
  • 1
  • 48
  • 63
  • 51
    @SanthoshKumar: Use `collection.ToList().ForEach(c => { c.Property1ToSet = value1; c.Property2ToSet = value2; });` – Ε Г И І И О Jul 28 '13 at 06:45
  • @CameronMacFarland: Of course it won't since structs are immutable. But if you really want, you can do this: `collection.ToList().ForEach(c => { collection[collection.IndexOf(c)] = new () { = value, = c.Property2Retain }; });` – Ε Г И І И О Nov 10 '13 at 10:53
  • 12
    This has the advantage over Cameron MacFarland's answer of updating the list in place, rather than creating a new list. – Simon Elms Jun 24 '16 at 10:16
  • 13
    Wow, this answer is really not useful. Creating a new collection just to be able to use a loop – Tim Schmelter Nov 16 '17 at 10:35
  • @SimonTewsi Since it is a collection of objects, the list should be updated in place anyways. The collection will be new, but the objects in the collection will be the same. – Chris Oct 03 '18 at 15:59
  • I have a problem with a list in which the first and last objects do not get updated.. any clues anyone? – Erik Thysell Nov 29 '18 at 06:41
  • @Erik Thysell Copy your code here. Did you use foreach? – Ε Г И І И О Nov 29 '18 at 12:44
  • How can add a Where clause? Thanks – Diego Dec 21 '18 at 16:16
  • @Diego Chain your Where clause before the ToList(). – Ε Г И І И О Feb 06 '19 at 06:47
  • 3
    this answer is simply incorrect: it does not actually change the original collection, it just creates a new one that you still need to assign somewhere – Allie Jun 28 '21 at 09:46
  • 3
    @Allie: Your criticism is correct, but this is only an issue if the elements in the collection are value types (i.e., structs). If `c` is a reference type, then setting `PropertyToSet` in this manner behaves as intended. See https://pastebin.com/rtG2i1KX – Brian Jul 01 '21 at 16:28
83

I am doing this

Collection.All(c => { c.needsChange = value; return true; });
Snake Eyes
  • 16,287
  • 34
  • 113
  • 221
Rahul
  • 1,007
  • 8
  • 5
  • I think this is the cleanest way to do it. – wcm Oct 09 '13 at 15:08
  • 41
    This approach certainly works but it violates the intent of the `All()` extension method, leading to potential confusion when someone else reads the code. – Tom Baxter Oct 29 '15 at 16:29
  • This approach is better .Using All instead of using each loop – UJS Nov 06 '17 at 05:07
  • 2
    Definitely prefer this over calling ToList() unnecessarily, even if it's a little misleading about what it's using All() for. – iupchris10 Dec 20 '17 at 22:24
  • 1
    If you're using a collection like `List<>` that has it the`ForEach()` method is a much less cryptic way to accomplish this. ex `ForEach(c => { c.needsChange = value; })` – Dan Is Fiddling By Firelight Dec 05 '19 at 21:27
  • This is better than using `Select` with `ToList`. – TheCrazyProgrammer Jul 13 '20 at 15:30
  • All and Any is meant for conditional checking. It's better to use MyList.ForEach(q => { q.StartDate.AddHours(8); q.EndDate.AddHours(8); }); if there is a need to update multiple columns together. – TPG Jun 30 '21 at 13:54
  • in case of performance and efficiency is this method better than foreach?.. because for large list its annoying to use loop directly. – Rouzbeh Zarandi May 16 '22 at 07:19
  • This is even worse than the `Select`-solution that is highest voted. `All` is ment to perform a filter, not to perform side-effects. – MakePeaceGreatAgain May 27 '22 at 13:32
31

I actually found an extension method that will do what I want nicely

public static IEnumerable<T> ForEach<T>(
    this IEnumerable<T> source,
    Action<T> act)
{
    foreach (T element in source) act(element);
    return source;
}
Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
lomaxx
  • 113,627
  • 57
  • 144
  • 179
  • 4
    nice :) Lomaxx, maybe add an example so peeps can see it in 'action' (boom tish!). – Pure.Krome Apr 10 '09 at 10:51
  • 2
    This is the only useful approach if you really want to avoid a `foreach`-loop (for whatever reason). – Tim Schmelter Nov 17 '17 at 08:46
  • @Rango which you are still NOT avoiding `foreach` as the code itself contains the `foreach` loop – GoldBishop Nov 27 '18 at 21:11
  • @GoldBishop sure, the method hides the loop. – Tim Schmelter Nov 27 '18 at 21:46
  • 1
    The link is broken, it is now available at: http://www.codewrecks.com/blog/index.php/2008/08/13/linq-foreach-for-ienumerablet/ . There's also a blog comment that links to https://stackoverflow.com/questions/200574/ . In turn, the top question comment links to https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/ . Perhaps the answer would be simpler re-written using the MSDN (you could still credit the first link if you wanted). Sidenote: Rust has similar features, and eventually gave in and added the equivalent function: https://stackoverflow.com/a/50224248/799204 – sourcejedi Nov 20 '19 at 12:11
  • 1
    The MSDN blog sourcejedi linked to, at https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/, has a good explanation of why the author thought it was a bad idea to create such an extension method. The author's most convincing reason, to me, is that using such an extension method doesn't really save many keystrokes compared to a plain foreach loop. Loop: `foreach(Foo foo in foos){ statement involving foo; }` Extension method: `foos.ForEach((Foo foo)=>{ statement involving foo; });` – Simon Elms Nov 24 '19 at 00:39
  • FYI this is a bad idea and can lead to unexpected behaviour. If you would use a method like this, it should be a `void` method. The problem is that this is effectively a "realize the collection" method that pretends to be an "add more lazy processing" method. It's a non-lazy process that pretends to be lazy. – Dave Cousineau Aug 27 '21 at 20:00
  • In particular you can end up with a duplicated set of objects, because the items that you're iterating over in this `foreach` loop are not necessarily the same ones that you will encounter after this method. (ie: if part of the previous lazy processing created the objects, then that creation will happen twice.) (The real problem I guess is both realizing the collection, *and* returning a lazy continuance of it, meaning that you will potentially realize the collection more than once.) – Dave Cousineau Aug 27 '21 at 20:02
26

Use:

ListOfStuff.Where(w => w.Thing == value).ToList().ForEach(f => f.OtherThing = vauleForNewOtherThing);

I am not sure if this is overusing LINQ or not, but it has worked for me when wanting to update a specific items in the list for a specific condition.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hennish
  • 685
  • 6
  • 10
23

Although you specifically asked for a LINQ solution and this question is quite old I post a non-LINQ-solution. This is because LINQ (= language integrated query) is meant to be used for queries on collections. All LINQ-methods don’t modify the underlying collection, they just return a new one (or more precise an iterator to a new collection). Thus whatever you do e.g. with a Select doesn’t effect the underlying collection, you simply get a new one.

Of course you could do it with a ForEach (which isn't LINQ, by the way, but an extension on List<T>). But this literally uses foreach anyway, but with a lambda-expression. Apart from this every LINQ method internally iterates your collection e.g. by using foreach or for, however it simply hides it from the client. I don’t consider this any more readable nor maintainable (think of edit your code while debugging a method containing lambda-expressions).

Having said this shouldn't use LINQ to modify items in your collection. A better way is the solution you already provided in your question. With a classic loop you can easily iterate your collection and update its items. In fact all those solutions relying on List.ForEach are nothing different, but far harder to read from my perspective.

So you shouldn't use LINQ in those cases where you want to update the elements of your collection.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • 4
    Off-topic: I agree, and there are sooooooo many instances of LINQ being abused, examples of people requesting "high performance LINQ chains", to do what could be accomplished with a single loop, etc. I am thankful that NOT using LINQ is too ingrained into me, and typically do not use it. I see people using LINQ chains to perform a single action, not realizing that pretty much every time a LINQ command is used you are creating another `for` loop "under the hood". I feel it is syntatic sugar to create less verbose ways of doing simple tasks, not to be a replacement for standard coding. – ForeverZer0 Jul 25 '18 at 07:27
  • 1
    so exactly where is your answer in all of that? – John Lord Sep 21 '21 at 14:54
  • 1
    @JohnLord the answer simply is: don't use LINQ in those cases where you want to modify the collection. – MakePeaceGreatAgain Sep 21 '21 at 18:03
10

There is no built-in extension method to do this. Although defining one is fairly straight forward. At the bottom of the post is a method I defined called Iterate. It can be used like so

collection.Iterate(c => { c.PropertyToSet = value;} );

Iterate Source

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, (x, i) => callback(x));
}

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, callback);
}

private static void IterateHelper<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    int count = 0;
    foreach (var cur in enumerable)
    {
        callback(cur, count);
        count++;
    }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Is Iterate necessary, whats wrong with Count, Sum, Avg or other existing extension method that returns a scalar value? – AnthonyWJones Dec 29 '08 at 22:32
  • 2
    this is pretty close to what i want but a little.. involved. The blog post I posted has a similar implementation but with fewer lines of code. – lomaxx Dec 29 '08 at 22:57
  • 1
    The IterateHelper seems overkill. The overload that doesn't take an index ends up doing alot more extra work (convert callback to lambda which takes index, keep a count which is never used). I understand it's reuse, but it's a workaround for just using a forloop anyway so it should be efficient. – Cameron MacFarland Dec 29 '08 at 23:20
  • 2
    @Cameron, IterateHelper serves 2 purposes. 1) Single implementation and 2) allows for ArgumentNullException to be thrown at call time vs. use. C# iterators are delayed executed, having the helper prevents the odd behavior of an exception being thrown during iteration. – JaredPar Dec 30 '08 at 03:42
  • 2
    @JaredPar: Except you're not using an iterator. There's no yield statement. – Cameron MacFarland Dec 30 '08 at 07:27
  • @Cameron, Doh, This is a part of a collection of extension methods I own and it's the only one that doesn't use an iterator. In either case, the extra overhead is negligible. – JaredPar Dec 30 '08 at 14:25
7

I've tried a few variations on this, and I keep going back to this guy's solution.

http://www.hookedonlinq.com/UpdateOperator.ashx

Again, this is somebody else's solution. But I've compiled the code into a small library, and use it fairly regularly.

I'm going to paste his code here, for the off chance that his site(blog) ceases to exist at some point in the future. (There's nothing worse than seeing a post that says "Here is the exact answer you need", Click, and Dead URL.)

    public static class UpdateExtensions {

    public delegate void Func<TArg0>(TArg0 element);

    /// <summary>
    /// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="update">The update statement to execute for each element.</param>
    /// <returns>The numer of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (update == null) throw new ArgumentNullException("update");
        if (typeof(TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        int count = 0;
        foreach (TSource element in source)
        {
            update(element);
            count++;
        }
        return count;
    }
}



int count = drawingObjects
        .Where(d => d.IsSelected && d.Color == Colors.Blue)
        .Update(e => { e.Color = Color.Red; e.Selected = false; } );
granadaCoder
  • 26,328
  • 10
  • 113
  • 146
  • 1
    You can use an `Action` instead of creating the an extra delegate. That might not have been available as of the time of writing that, though. – Frank J May 01 '15 at 15:20
  • Yeah, that was old school DotNet at that point in time. Good comment Frank. – granadaCoder Mar 01 '19 at 15:59
  • The URL is dead ! (This Domain Name Has Expired) Good thing I copied the code here ! #patOnShoulder – granadaCoder Mar 01 '19 at 16:01
  • 1
    Checking for value type makes sense, but perhaps it would be better to use a constraint, i.e. `where T: struct`, to catch this at compile time. – vgru Nov 21 '19 at 08:49
6

Some people consider this is a comment, but for me is an answer, because the right way to do something wrong is not do it. So, the answer for this question is in the question itself.

DO NOT USE LINQ to modify data. Use a loop.

Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
5

No, LINQ doesn't support a manner of mass updating. The only shorter way would be to use a ForEach extension method - Why there is no ForEach extension method on IEnumerable?

Community
  • 1
  • 1
Aaron Powell
  • 24,927
  • 18
  • 98
  • 150
2

I wrote some extension methods to help me out with that.

namespace System.Linq
{
    /// <summary>
    /// Class to hold extension methods to Linq.
    /// </summary>
    public static class LinqExtensions
    {
        /// <summary>
        /// Changes all elements of IEnumerable by the change function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <returns>An IEnumerable with all changes applied</returns>
        public static IEnumerable<T> Change<T>(this IEnumerable<T> enumerable, Func<T, T> change  )
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");

            foreach (var item in enumerable)
            {
                yield return change(item);
            }
        }

        /// <summary>
        /// Changes all elements of IEnumerable by the change function, that fullfill the where function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should be made</param>
        /// <returns>
        /// An IEnumerable with all changes applied
        /// </returns>
        public static IEnumerable<T> ChangeWhere<T>(this IEnumerable<T> enumerable, 
                                                    Func<T, T> change,
                                                    Func<T, bool> @where)
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");
            ArgumentCheck.IsNullorWhiteSpace(@where, "where");

            foreach (var item in enumerable)
            {
                if (@where(item))
                {
                    yield return change(item);
                }
                else
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Changes all elements of IEnumerable by the change function that do not fullfill the except function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should not be made</param>
        /// <returns>
        /// An IEnumerable with all changes applied
        /// </returns>
        public static IEnumerable<T> ChangeExcept<T>(this IEnumerable<T> enumerable,
                                                     Func<T, T> change,
                                                     Func<T, bool> @where)
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");
            ArgumentCheck.IsNullorWhiteSpace(@where, "where");

            foreach (var item in enumerable)
            {
                if (!@where(item))
                {
                    yield return change(item);
                }
                else
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> Update<T>(this IEnumerable<T> enumerable,
                                               Action<T> update) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");
            foreach (var item in enumerable)
            {
                update(item);
            }
            return enumerable;
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// where the where function returns true
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <param name="where">The function to check where updates should be made</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> UpdateWhere<T>(this IEnumerable<T> enumerable,
                                               Action<T> update, Func<T, bool> where) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");
            foreach (var item in enumerable)
            {
                if (where(item))
                {
                    update(item);
                }
            }
            return enumerable;
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// Except the elements from the where function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should not be made</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> UpdateExcept<T>(this IEnumerable<T> enumerable,
                                               Action<T> update, Func<T, bool> where) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");

            foreach (var item in enumerable)
            {
                if (!where(item))
                {
                    update(item);
                }
            }
            return enumerable;
        }
    }
}

I am using it like this:

        List<int> exampleList = new List<int>()
            {
                1, 2 , 3
            };

        //2 , 3 , 4
        var updated1 = exampleList.Change(x => x + 1);

        //10, 2, 3
        var updated2 = exampleList
            .ChangeWhere(   changeItem => changeItem * 10,          // change you want to make
                            conditionItem => conditionItem < 2);    // where you want to make the change

        //1, 0, 0
        var updated3 = exampleList
            .ChangeExcept(changeItem => 0,                          //Change elements to 0
                          conditionItem => conditionItem == 1);     //everywhere but where element is 1

For reference the argument check:

/// <summary>
/// Class for doing argument checks
/// </summary>
public static class ArgumentCheck
{


    /// <summary>
    /// Checks if a value is string or any other object if it is string
    /// it checks for nullorwhitespace otherwhise it checks for null only
    /// </summary>
    /// <typeparam name="T">Type of the item you want to check</typeparam>
    /// <param name="item">The item you want to check</param>
    /// <param name="nameOfTheArgument">Name of the argument</param>
    public static void IsNullorWhiteSpace<T>(T item, string nameOfTheArgument = "")
    {

        Type type = typeof(T);
        if (type == typeof(string) ||
            type == typeof(String))
        {
            if (string.IsNullOrWhiteSpace(item as string))
            {
                throw new ArgumentException(nameOfTheArgument + " is null or Whitespace");
            }
        }
        else
        {
            if (item == null)
            {
                throw new ArgumentException(nameOfTheArgument + " is null");
            }
        }

    }
}
2

You can use LINQ to convert your collection to an array and then invoke Array.ForEach():

Array.ForEach(MyCollection.ToArray(), item=>item.DoSomeStuff());

Obviously this will not work with collections of structs or inbuilt types like integers or strings.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
1

You can use Magiq, a batch operation framework for LINQ.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ivos
  • 47
  • 1
1

Here is the extension method I use...

    /// <summary>
    /// Executes an Update statement block on all elements in an  IEnumerable of T
    /// sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="action">The action method to execute for each element.</param>
    /// <returns>The number of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> action)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (action == null) throw new ArgumentNullException("action");
        if (typeof (TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        var count = 0;
        foreach (var element in source)
        {
            action(element);
            count++;
        }
        return count;
    }
Bill Forney
  • 786
  • 7
  • 16
  • Why "value type elements are not supported by update"?? Nothing interferes that! – abatishchev Aug 17 '10 at 14:13
  • That was specific to the project I was working on. I suppose it wouldn't matter in most cases. Lately I've reworked that and renamed it Run(...), removed the value type thing and changed it to return void and dropped the count code. – Bill Forney Oct 22 '10 at 04:44
  • That´s more or less what `List.ForEach` also does, but just for all `IEnumerable`. – MakePeaceGreatAgain Jul 25 '18 at 07:36
  • Looking back on this now I'd say just use a foreach loop. The only benefit of using something like this is if you want to chain the methods together and return the enumerable from the function to continue the chain after executing the action. Otherwise this is just an extra method call for no benefit. – Bill Forney Sep 07 '18 at 18:51
0

I assume you want to change values inside a query so you could write a function for it

void DoStuff()
{
    Func<string, Foo, bool> test = (y, x) => { x.Bar = y; return true; };
    List<Foo> mylist = new List<Foo>();
    var v = from x in mylist
            where test("value", x)
            select x;
}

class Foo
{
    string Bar { get; set; }
}

But not shure if this is what you mean.

Stormenet
  • 25,926
  • 9
  • 53
  • 65
0

My 2 pennies:-

 collection.Count(v => (v.PropertyToUpdate = newValue) == null);
AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
-1

Quoting Adi Lester's answer (https://stackoverflow.com/a/5755487/8917485)

I quite like this answer, but this answer has a bug. It just changes values in a new created list. It must be changed to two lines to read the real changed list.

var aList = collection.ToList();
aList.ForEach(c => c.PropertyToSet = value);
江明哲
  • 27
  • 5
  • This should have been a comment. Please wait until you can comment properly. But also, it's not true. The statement `collection.ToList().ForEach(c => c.PropertyToSet = value)` permanently changes all items in `collection`, it doesn't matter in which way they happen to get enumerated. – Gert Arnold Apr 18 '22 at 10:51
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31561721) – Kuro Neko Apr 21 '22 at 08:31
-4

Suppose we have data like below,

var items = new List<string>({"123", "456", "789"});
// Like 123 value get updated to 123ABC ..

and if we want to modify the list and replace the existing values of the list to modified values, then first create a new empty list, then loop through data list by invoking modifying method on each list item,

var modifiedItemsList = new List<string>();

items.ForEach(i => {
  var modifiedValue = ModifyingMethod(i);
  modifiedItemsList.Add(items.AsEnumerable().Where(w => w == i).Select(x => modifiedValue).ToList().FirstOrDefault()?.ToString()) 
});
// assign back the modified list
items = modifiedItemsList;
Vishwa G
  • 573
  • 1
  • 6
  • 13
  • 2
    Why would you make something which can run in O(n) runtime execute in O(n^2) or worse? IM unaware of how specifics of linq work but i can see this is at minimum a n^2 solution for a *n* problem. – Fallenreaper Mar 27 '19 at 14:06