1

I'm trying to test just how far LINQ can really go. What i'm trying to achieve is property assignments on a list of objects with a single expression rather than for loops. I want to take all items in listA and update the IsMatched property, but only where there is a corresponding item in listB (which is a different type), is this possible?

Sample Code:

public struct A { public int x; public bool IsMatched;}
public struct B {public int x;}

static void Main(string[] args)
{
  List<A> listA = new List<A>(); 
  List<B> listb = new List<B>();
  listA.Add(new A() { x=1}); 
  listA.Add(new A() { x=2}); 
  listA.Add(new A() { x=3});

  listb.Add(new B() { x=2}); 
  listb.Add(new B() { x=3});

  listA = listA.SelectMany(fb => listb, (fb, j) => new {a=fb, b=j})
        .Where (anon => anon.b.x == anon.a.x).Select(anon => new A() {x=anon.a.x, IsMatched=true})
        .ToList(); // this does not do what I want.

}

I've tried using SelectMany but this only returns the items that matched, or a Cartesian product which I don't want.

James
  • 12,636
  • 12
  • 67
  • 104
  • 1
    On the subject of side-effects, see http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx – Ian Mercer Oct 29 '10 at 04:49

1 Answers1

5

LINQ wasn't designed to cause side-effects. In this case, modify items in a collection. Just create the query to select the items you want to modify, then loop through the items modifying them as necessary.

var query = from a in listA
            join b in listB on a.x equals b.x
            select a;
foreach (var a in query)
    a.IsMatched = true;

You can cheat however and formulate a lambda to cause the side-effect. Then use it an an aggregation method. But you shouldn't do this in practice however.

(from a in listA
 join b in listB on a.x equals b.x
 let modify = new Func<A,A>(m => { m.IsMatched = true; return m; })
 select modify(a)).ToArray();
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • @Jeff M - Thanks - Apparently assignments can be done inside of an anonymous method check [this](http://stackoverflow.com/questions/807797/linq-select-an-object-and-change-some-properties-without-creating-a-new-object) out, just read it myself. This gets me halfway at least. – James Oct 29 '10 at 04:46
  • @Jeff M - Sorry I need to read more carefully next time ;). Why is doing that considered a bad practice? – James Oct 29 '10 at 04:56
  • @James: As mentioned in the first part, ;) LINQ wasn't really designed to do cause side affects, just operate on sets of data. – Jeff Mercado Oct 29 '10 at 05:00
  • @Jeff M - That doesn't really explain why it's a bad practice, given the fact that it can be done without much hassle. – James Oct 29 '10 at 05:10
  • @James: Just because there's nothing stopping you, doesn't mean you should do it. I'm not sure I can adequately explain why. Perhaps [Eric Lippert's](http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx) article which explains why there isn't a `ForEach()` extension method (which is effectively what we're doing here) can explain enough. – Jeff Mercado Oct 29 '10 at 05:18