tags:

views:

93

answers:

4

I have a collection of Obj's, I want to go through the collection, and set a property if a condition is true, so in normal world it would be:

foreach (var o in obj)
{
   if (o.SomeProperty == Something)
   {
      o.SomeOtherProperty = true;
   }
}

Anyway to do this, using Linq, to make it in a single line?

+5  A: 

LINQ isn't all that useful for executing side effects, it's primarily intended for querying. In truth, the fact that it has deferred execution so engrained in its behaviour makes it a poor choice for executing side-effects, IMO.

The code you've got looks perfectly fine to me. If you did want to use LINQ though, I doubt you could improve much on:

foreach (var o in obj.Where(i => i.SomeProperty == Something))
{
   o.SomeOtherProperty = true;
}  

Now, that isn't all that better (arguably worse) than your original.

On the other hand, if you wanted to create a new, streaming sequence with projections of the original items having the desired characteristics, you could do something like:

var projection = obj.Where(i => i.SomeProperty == Something)
                    .Select(i => new Foo(i) { SomeOtherProperty = true });
                    // assuming your type has a copy-constructor

EDIT: If you don't want to heed the advice of the experts (read: Eric Lippert), you can write your own extension-method:

public static void Do<T>(this IEnumerable<T> source, Action<T> action)
{ 
  if (source == null)
     throw new ArgumentNullException("source");

  if (action == null)
     throw new ArgumentNullException("action");

  foreach (T item in source) 
     action(item);
}

This will allow you to do:

obj.Where(o => o.SomeProperty == Something)
   .Do(o => o.SomeOtherProperty = true);
Ani
I've never seen the term "copy constructor" used in the C# context.
Gabe
@Gabe: Haha, I just guessed it's called that in C# too. Is there a more appropriate term for it?
Ani
You don't hear about copy constructors in C# because C# doesn't use them. You can create `public Foo(Foo copy)` constructors, but since the compiler doesn't implicitly generate calls to them, it doesn't matter whether they actually produce copies (as they must in C++). If your C# constructor actually does create a copy, I suppose "copy constructor" is a cromulent term for it.
Gabe
@Gabe: Just found this: http://msdn.microsoft.com/en-us/library/ms173116(VS.80).aspx
Ani
+3  A: 
obj.Where(i => i.SomeProperty == Something).ToList().ForEach(o => o.SomeOtherProperty = true);  
Richard Hein
Don't do this... http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx
Mehrdad Afshari
I agree it's not a 'good' thing to do; but incidentally, it can be done with less code than above. :P
Andrew Barber
@Andrew How would you do it with less code?
Richard Hein
I posted my answer also; it takes advantage of the fact that the example property being set is a bool to avoid needing to narrow the list. Since every item in the original list has to be iterated anyway in order to do the test, it seemed like a decent way to do a not-so-good thing.
Andrew Barber
@Andrew Ah, I see, tricky, but you mixed up SomeProperty and SomeOtherProperty employing your trickiness. ;) Plus you need ToList, assuming myCollection is an IEnumerable.
Richard Hein
A: 

You could do this:

myCollection.ForEach(item => 
    if(item.SomeProperty==Something){item.SomeOtherProperty = true});

But I wouldn't recommend it; you're not really saving much at all, and it loses a little bit of readability, IMO.

Andrew Barber
Note that this does not necessarily have equivalent behavior to the original code, since it sets `item.SomeProperty` to `false` if `item.SomeOtherProperty` is not `Something`, whereas the original code leaves `item.SomeProperty` alone in that case.
kvb
+1  A: 

Using an extension method:

public static int UpdateOnPredication<T>(this IEnumerable<T> source, Func<T, bool> predicate, Action<T> update)
{
    //check the parameters here if (source==null) ...
    var query = source.Where(predicate);
    foreach (var item in query)
    {
        update(item);
    }
    return query.Count();
}

Usage:

results.UpdateOnPredication(x => x.ID > 1000, x => x.Status = 1);
Danny Chen