If only I were

Building Great Software

Func<T> based Generic List Initializers

with 7 comments

A couple of weeks ago I was writing some code to initialize List<T> but my technique was very verbose and it seemed to be a distraction from what I was trying to do. Plus it seemed that every one else was writing about getting their func on.

So I looked back at some code that Nick Parker had written:

   1: public class Builder
   2: {
   3:     public static TType Create<TType>(Action<TType> actionOnTType) where TType : new()
   4:     {
   5:         var item = new TType();
   6:         actionOnTType(item);
   7:         return item;
   8:     }
   9: }

And tweaked it to initialize a list:

   1: public class Builder
   2: {
   3:     public static List<TType> CreateList<TType>(long size, Func<TType> initExpression)
   4:     {
   5:         var items = new List<TType>();
   6:         for (long i = 0; i < size; i++)
   7:         {
   8:             TType item = initExpression();
   9:             items.Add(item);
  10:         }
  11:
  12:         return items;
  13:     }
  14: }

Now I can initialize a list like this:

   1: List<Door> doors = Builder.CreateList(100, () => new Door {IsOpen = false});

Just for the record the Func initialization above could handle much more complex scenarios if needed. My usage is very simple.

Another variation on this is to create an extension method that does the same initialization like this:

   1: public static void Init<TType>(this IList<TType> values, int size, Func<TType> initExpression)
   2: {
   3:     for (int i = 0; i < size; i++)
   4:     {
   5:         TType item = initExpression();
   6:         values.Add(item);
   7:     }
   8: }

And here is how you would use the extension method version:

   1: var doors = new List<Door>();
   2: doors.Init(10, () => new Door());

Thanks to Nick Parker for some suggestions as I was working on this.

Something I would like to figure out is how to do this based on IEnumerable instead of IList. If you have ideas regarding implementing this on IEnumerable please add them as comments.

Also, if you want to see where I was using this, pull down the subversion source here: http://subversion.assembla.com/svn/solon-tools/trunk/Puzzles

kick it on DotNetKicks.com

About these ads

Written by Chris Sutton

December 6, 2008 at 1:19 pm

Posted in Learning, Technology

Tagged with , ,

7 Responses

Subscribe to comments with RSS.

  1. Chris, you can’t do the same thing with an IEnumerable because member assignment is not defined in that interface. If you want something a little more generic you can convert your code to ICollection pretty easily but I’m afraid that will be as far as you can go.
    Since I’m a compulsive suggestion provider, I couldn’t pass the opportunity to tweak your code. Changing the extension method to return the original collection and the delegate to accept the current index (maybe just an overloaded version of the same method):

    public ICollection void Init(this ICollection values, int size,
    Func initExpression)
    {
    for (int i = 0; i < size; i++)
    {
    T item = initExpression(i);
    values.Add(item);
    }
    return values;
    }

    Then you could write something like:

    var doors = new List().Init(10, i => new Door{ Name = “Door #” + i });

    I’d probably also rename the method to Add since the list might not be empty to begin with.

    Sergio Pereira

    December 6, 2008 at 2:26 pm

  2. For what it’s worth, F#’s List.init also accepts the index in its generator.

    How about Builder.Init with deferred execution:
    public static IEnumerable Init(long size, Func generator)
    {
    for (long i = 0; i new Door { Name = “Door #”+i }).ToList();

    Or without an intermediate data structure:
    foreach(var sq in Builder.Init(10, i => new { Num = i, IsEven = (0 == i % 2) }))

    And for fun, an interesting take on an example from PuzzleMath.cs:
    public static IEnumerable Squares {
    get {
    for (long i = 0, sq = 0; sq <= long.MaxValue; sq = (++i) * i)
    yield return sq;
    }
    }

    public static IEnumerable FindPerfectSquares(long max)
    {
    return Squares.Where(i => i <= max);
    }

    Cheers ~
    Keith

    Keith Dahlby

    January 7, 2009 at 1:29 pm

  3. Apparently WordPress thought I was trying to post HTML… Trying again.

    How about Builder.Init with deferred execution:
    public static IEnumerable<T> Init<T>(long size, Func<long, T> generator)
    {
    for (long i = 0; i < size; i++)
    yield return generator(i);
    }

    Which could be used to build a List…
    var doors = Builder.Init(10, i => new Door { Name = “Door #”+i }).ToList();

    Or without an intermediate data structure:
    foreach(var sq in Builder.Init(10, i => new { Num = i, IsEven = (0 == i % 2) }))

    And for fun, an interesting take on an example from PuzzleMath.cs:
    public static IEnumerable<long> Squares {
    get {
    for (long i = 0, sq = 0; sq FindPerfectSquares(long max)
    {
    return Squares.Where(i => i <= max);
    }

    Cheers ~
    Keith

    Keith Dahlby

    January 7, 2009 at 1:36 pm

  4. Missed one…

    And for fun, an interesting take on an example from PuzzleMath.cs:
    public static IEnumerable<long> Squares {
    get {
    for (long i = 0, sq = 0; sq <= long.MaxValue; sq = (++i) * i)
    yield return sq;
    }
    }

    public static IEnumerable<long> FindPerfectSquares(long max)
    {
    return Squares.Where(i => i <= max);
    }

    Keith Dahlby

    January 7, 2009 at 1:38 pm

  5. You can implement your IEnumerable as follows. If you observe the printed lines in your debug output, you will see that even though size is set to long.MaxValue, only the first 5 are ever created and returned since I used “Take(5)”, which enumerates the first 5.

    You will also see that the enumeration starts over when you call the doors enumerable again.

    public class Builder
    {
    public static IEnumerable<TType> CreateEnumerable<TType>(long size, Func<TType> initExpression)
    {
    for (long i = 0; i doors = Builder.CreateEnumerable<Door>(long.MaxValue, () => new Door { IsOpen = false });

    foreach (var i in doors.Take(5))
    {
    Debug.Print(“Enumerating”);
    }

    foreach (var i in doors.Take(5))
    {
    Debug.Print(“Enumerating”);
    }
    }

    David Walker (@Grax)

    May 6, 2013 at 9:23 pm

  6. I ɑm ѕure this piece of writing haas touched alll thhe internet users, іts reallү really ood adticle on building սp new webb site.

    psn download code

    July 17, 2014 at 5:27 pm

  7. For example, the “out of memory” exception error can be
    fixed by installing. Echo Cancelation: Mike and TV
    speakers are too close together to enable windows to supply echo cancellation. First of all, you need to understand that
    if your computer is really low on RAM to run certain programs,
    then you will constantly be having issues and freeze-ups.

    skype resolver legal

    July 20, 2014 at 6:36 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: