Tuesday, April 15, 2008

C# code snippets for lists

How many times do you enumerate your collections to perform some operations? How many times do you use following idiom?

List<T> list;
...
 
foreach ( T t in list )
{
  // do something with t
}

Isn't it boring?


It seems that the List<T> has a rather rarely used method, ForEach which can be used instead of C#'s foreach:



list.ForEach( t => // do something with t )

This looks especially refreshing when used for loops that initialize containers. Compare the usual version:



class Model {
  public List<Entity> Entities;
 
  public Model( int EntityCount ) {
    Entities = new List<Entity>();
 
    // usual container initialization rountine
    for ( int i=0; i<EntityCount; i++ ) {
      Entities.Add( new Entity() );
    }
  }
}


with the new one:


class Model {
  public List<Entity> Entities;
  
  public Model( int EntityCount ) {
    Entities = new List<Entity>();
 
    Enumerable
      .Range( 0, EntityCount )
      .ToList()
      .ForEach(
         i => Entities.Add( new Entity() )
      );
  }
}

Note that the for instruction is missing and instead Enumerable.Range with ForEach is used to get the same result.


One could surely argue if this new version is more readable but compare this one:



Model m = new Model();
 
foreach ( Entity e in m.Entities )
    foreach ( Subentity s in e.Subentities )
    {
         // do something with s
    }

and this one:



Model m = new Model();
 
m.Entities.ForEach( e => e.Subentities.ForEach( s => // do something with s ) );

Yet another interesting but rarely used pattern arises when literal representations of list items must be merged together to form a literal representation of the list. I often see something like that:



List<T> list;
...
 
StringBuilder sb = new StringBuilder();
foreach ( T t in list ) {
  sb.AppendFormat( "{0}, ", t );
}
// remove ending ", "
if ( sb.Length > 2 )
  sb.Remove( sb.Length - 2 );

while string.Join should be used to get the same result with much cleaner code:



List<T> list;
 
// first convert List<T> to List<string> using ConvertAll
// then convert List<string> to string[] expected by the string.Join
string result = 
  string.Join( ", ", list.ConvertAll( t => t.ToString() ).ToArray() );
Happy coding!

1 comment:

Krzysztof Koźmic said...

I use this method A lot! I went even one step further, and created similar extension method for IEnumerable>T<.
Adding lambdas to the equation, you can remove a great deal of code (without losing readability) which I think is a huge benefit.