0

I want to convert a nested foreach loop in C# to Linq. I know how to do it if the two lists are of same type. But in my case, they are of different type, except that they both have two common properties, DocumentId and IsValid. I have to loop through the outer list and the inner list and whenever the DocumentId of both are the same, then assign the IsValid value from the outer loop object to the inner loop object. I have the following foreach loop is working fine.

foreach (var docs in outerDocuments)
{
     foreach (var presentedDocuments in innerdocuments)
     {
           if (docs.DocumentId.Equals(presentedDocuments.DocumentId))
           {
                 presentedDocuments.IsValid = docs.IsValid;
           }
     }
}

I need to convert it to Linq. Usually ReSharper does a good job of refactoring such code. But in this case it converted only the nested foreach to Linq, and even then it threw a warning , "Access to foreach variable in closure".

Thanks

3
  • What makes you think you NEED to convert it to LINQ? Commented Oct 4, 2015 at 1:44
  • As you aren't putting out a new list, you're really just going to end up with the built in ForEach anyway. That's probably part of why ReSharper didn't clean it up Commented Oct 4, 2015 at 1:47
  • Hi Justin, that is a good point. Thanks Commented Oct 5, 2015 at 2:22

3 Answers 3

1

You can try using Enumerable.Join:

foreach (var item in outerDocuments.Join(innerdocuments,
                                         outer => outer.DocumentId,
                                         inner => inner.DocumentId,
                                         (outer, inner) => new { OuterDoc = outer, InnerDoc = inner }))
{
    item.InnerDoc.IsValid = item.OuterDoc.IsValid;
}
Sign up to request clarification or add additional context in comments.

Comments

0

Try this:

foreach (var presentedDocuments in innerdocuments)
{
    var doc = outerDocuments.FirstOrDefault(a => a.DocumentId.Equals(presentedDocuments.DocumentId));
    if (doc != null)
    {
        presentedDocuments.IsValid = doc.IsValid;
    }
}

Comments

0

You can use .Join() extension method and do it in one line like this:

outerDocuments.Join(innerDocuments, o => o.DocumentId, i => i.DocumentId, (o, i) =>  i.IsValid = o.IsValid).ToList();

As noted by @sstan .ToList() call is required to force enumeration.

3 Comments

Interesting idea. Not sure it's the best idea to have state changing code in the resultSelector parameter, it kind of goes against the spirit of how the join method is supposed to work. And in this case, it won't actually work unless you actually loop the result of your join call. If you add a call to ToList() at the end it will work.
@Enigmativity I used LINQPad to test it and its' .Dump() extension method did ToList's work, that's why my test succeded. I updated code example as per @sstan suggestion.
@Vova - Until you forced execution it wouldn't work. The .ToList() (or .Dump()) would be needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.