tags:

views:

1402

answers:

8

It is not uncommon for me (or likely anyone else) to have a list of objects I need to iterate through and then interact with a list of properties. I use a nested loop, like this:

IList<T> listOfObjects;
IList<TProperty> listOfProperties;

foreach (T dataObject in listOfObjects)
{
    foreach (TProperty property in listOfProperties)
    {
        //do something clever and extremely useful here
    }
}

Is this the time and performance tested pattern for this problem? Or is there something more performant, more elegant, or just plain fun (while still being readable and maintainable of course)?

The code above doesn't make me smile. Can someone please help bring some joy to my loop?

Thank you!

Update: I use the term "nerd" in a most positive sense. As part of the wikipedia definition puts it "that refers to a person who passionately pursues intellectual activities". By "code nerd" I mean someone who is concerned about continually improving oneself as a programmer, finding new, novel, and elegant ways of coding that are fast, maintainable, and beautiful! They rejoice to move out of VB6 and want smart people to critique their code and help them smartify themselves. (Note: they also like to make new words that end in -ify).

Final note:

Thank you to Dave R, Earwicker, and TheSoftwareJedi for sending me down the Linq path. It is just the sort of happy code I was looking for!

A: 

In such a scenario, we often start by filtering the pieces we're interested in. your block dosomethingclever() usually starts in

foreach (T dataObject in listOfObjects)
{    
  foreach (TProperty property in listOfProperties)    
  {
    if (property.something == "blah") 
    { // OK, we found the piece we're interested in...

      // do something clever...

    }
  }
}

This is where LINQ is your friend, allowing your to replace your loops by a select statement. Of course you may still need to iterate on the results set.

Tons of samples here.

Serge - appTranslator
+3  A: 

If you need to do something with every object and every property, there's not a lot to be done. You might be able to do some syntactically pleasing things, but there's not a way around doing the work.

If you are only doing work on a subset of the objects and/or properties, filter it (with linq to objects, if you're doing .net 3.5)!

You might enjoy Filter/Map/Reduce for your sets as a means of introducing better syntax to doing set operations.

Joel Meador
I think he's doing work on some cartesian joined result of the lists, so what he'd doing need not be criticized. He's just looking for a more elegant way of writing it.Nested loops suck.
TheSoftwareJedi
@TheSoftwareJedi - Why do nested loops suck? I would like to hear your reasoning.
kirk.burleson
+7  A: 

There is certainly nothing wrong with nested loops. They are fast, readable and have been around since software development took its first baby steps.

As you want to perform actions as you iterate over a collection, you may find that LINQ would be an interesting avenue to explore:

http://msdn.microsoft.com/en-us/vcsharp/aa904594.aspx

You'll be limiting yourself to later versions of the Framework (3.5 onwards), but you may actually find the Functional Programming approach quite elegant. Other language features that come into play when you go down this road include lambdas and anonymous methods, which are fascinating in their own right.

Best of luck and I hope you have fun on the way - that's a great approach :)

Dave R.
Nested loops can be a bear to read. Linq helps with that.
TheSoftwareJedi
Wonderful answer. Of course, those who think nested loops are unreadable, like TheSoftwareJedi, may find them hard to read. Although I don't see why.
kirk.burleson
+4  A: 
foreach (var pair in from obj in listOfObjects
                     from prop in listOfProperties  
                     select new {obj, prop})
{
   Console.WriteLine(pair.obj + ", " + pair.prop);
}
Daniel Earwicker
+6  A: 

Looks like you are trying to cartesian join two lists, and apply a where clause. Here's a simple example showing the Linq syntax for doing this, which I think is what you are looking for. list1 and list2 can be any IEnumerable, your where clause can contain more detailed logic, and in your select clause you can yank out what you need.

        var list1 = Enumerable.Range(1, 100);
        var list2 = Enumerable.Range(1, 100);

        foreach (var item in from a in list1
                             from b in list2
                             where a % b == 0
                             select new { a, b })
        {
            Console.WriteLine(item);
        };

Performance will be identical to what you posted though - no desire to mislead on that respect. I do prefer this Linq syntax.

TheSoftwareJedi
+1  A: 
Action<T, TProp> somethingClever = //your clever method

listOfObjects
  .SelectMany(
    o => listOfProperties,
    (o, p) => new {o, p})
  .ToList()
  .ForEach(x => somethingClever(x.o, x.p));
David B
This looks even more nerdy! Oh the options for happy code! Now, to convince team lead to allow transition to 3.5 :(
MrJeepster
A: 

I like Ayende's pipes and filters, but it's a lot more code than built-in LINQ for simple loops (I assume the code example in the question was trivial).

Anthony Mastrean
+2  A: 

While I do like the elegance of the Linq solutions, I think my recommendation would be to extract the inner loop into a method; Your code would end up looking something like:

foreach(dataObject in listOfObjects)
    DoSomethingCleverWithProperties(dataObject, listOfProperties);

That just feels more maintainable to me.

Chris Shaffer