dhouse42
dhouse42

Reputation: 13

How to simplify multiple nested foreachs in c#

Basically I have a method that is passed a list of custom objects. I'm using C#. Each of these contains a name and another list of other custom objects, I'll call these subObjects. These each have a name and a list of strings. I need to loop through all the strings, but keep track of the names of the parent object and subject for error logging purposes. Is there a cleaner, nicer way to do this than nesting foreachs?

foreach (var obj in listOfObjects) 
{
    foreach (var subObj in obj.subObjects)
    {
        foreach (var aString in subObj.strings)
        {
            if (some condition applies) 
            {
                //log error that includes obj, subObj, and subSubObj names, and aString.
            }
        }
    }
}

Upvotes: 1

Views: 1649

Answers (3)

Exorion
Exorion

Reputation: 25

The way I do it :

foreach (YourClass something in YourObject.SelectMany(x => x.Nested).SelectMany(x => x.MoreNesting)) {
    // Do Stuff Here
}

Probably not the best way to do it or whatever, it's just the clearest way for me, while avoiding the triple nesting look I don't quite like.

Upvotes: -1

Trevor Ash
Trevor Ash

Reputation: 633

Adding to MarcinJuraszek answer, if linq to objects is preferred...

var errors = listOfObjects
  .SelectMany(obj => obj.subObjects
    .SelectMany(subObj => subObj.strings
      .Where(r => /* your condition */)
      .Select(aString => new { obj, subObj, aString })));

But there's nothing wrong with the code you posted. Clearly, yours is easier to follow at a quick glance.

Upvotes: 0

MarcinJuraszek
MarcinJuraszek

Reputation: 125620

You can write a LINQ query to get all error cases

var errors = from obj in listOfObjects
             from subObj in obj.subObjects
             from aString in subObj.strings
             where /* your condition */
             select new { obj, subObj, aString };

and than iterate over them only:

foreach(var errorCase in errors)
{
    // log your error
}

or get the first one:

var error = errors.FirstOrDefault();

depending on your needs.

Upvotes: 3

Related Questions