3

I'd like to ask if it is possible to convert below nested foreach loops to LINQ expression.

public interface IFoo
{
  bool IsCorrect(IFoo foo);
  void DoSomething(IFoo foo);
}

List<IFoo> listA; //assume that contains items
List<IFoo> listB; //assume that contains items


foreach (var a in listA)
{
  foreach (var b in listB)
  {
    if (b.IsCorrect(a))
    {
      b.DoSomething(a);
    }
  }
}
rgb
  • 1,750
  • 1
  • 20
  • 35

4 Answers4

4

This should work:

var result =
    from a in listA
    from b in listB
    where b.IsCorrect(a)
    select new {a, b};

foreach (var item in result)
    item.b.DoSomething(item.a);
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
2

With method syntax you would use this query:

var correctPairs = listA
    .SelectMany(a => listB.Where(b => b.IsCorrect(a)).Select(b => new { a, b }));

foreach (var x in correctPairs)
    x.b.DoSomething(x.a);
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

I'm not sure exactly how far you want to go with this, but this is a Linq statement doing the same thing:

listA.ForEach(a => listB.ForEach(b =>
{
    if (b.IsCorrect(a)) b.DoSomething(a);
}));
LordWilmore
  • 2,829
  • 2
  • 25
  • 30
  • 3
    Actually, this answer has nothing to do with with LINQ. – itsme86 Nov 23 '16 at 16:27
  • 1
    @itsme86 Very true. I always thought the ForEach method was a linq extension, but it appears that it is not! – LordWilmore Nov 23 '16 at 16:29
  • If you want a linq Foreach, this will give it to you: public static partial class FunctionalExtensions { public static void ForEach(this IEnumerable items, Action action) { foreach (T item in items) action(item); } public static IEnumerable ForEach(this IEnumerable items, Func action) { foreach (T item in items) { yield return action(item); } } } – Jim Nov 23 '16 at 17:17
  • 2
    @Jim That would involve no more LINQ than this method. Nor is it representative of a LINQ style of programming. In fact, it's very specifically *contrary* to the LINQ style of programming. – Servy Nov 23 '16 at 21:13
1

You can do this but this is not more efficient what you have so far:

var query= listA.SelectMany(a=>listB.Select(b=>new {a,b}))
                .Where(e=>e.b.IsCorrect(e.a))
                .ToList()// Foreach is a method of List<T>
                .Foreach(e=> e.b.DoSomething(e.a));

To avoid to call ToList, you can implement an extension method like this:

public static void ForEach<T>(this System.Collection.Generic.IEnumerable<T> list, System.Action<T> action)
{
    foreach (T item in list)
        action(item);
}

And then your query would be:

var query= listA.SelectMany(a=>listB.Select(b=>new {a,b}))
                .Where(e=>e.b.IsCorrect(e.a))
                .Foreach(e=> e.b.DoSomething(e.a));
ocuenca
  • 38,548
  • 11
  • 89
  • 102