tags:

views:

52

answers:

1

I have an object containing a date and a count.

 public class Stat
 {
    public DateTime Stamp {get; set;}
    public int Count {get; set ;}
 }

I have a Serie object that holds a list of thoses Stat plus some more info such as name and so on...

public class Serie
{
    public string Name { get; set; }
    public List<Stat> Data { get; set; }
    ...
}

Consider that I have a List of Serie but the series don't all contain the same Stamps. I need to fill in the missing stamps in all series with a default value.

I thought of an extension method with signature like this (please provide better name if you find one :) ) :

 public static IEnumerable<Serie> Equalize(this IEnumerable<ChartSerie> series, int defaultCount)

this question seems to treat the same problem, but when querying directly the DB. of course I could loop through the dates and create another list. But is there any more elegant way to achieve this?

i.e.:

Serie A:
01.05.2010 1
03.05.2010 3

Serie B:
01.05.2010 5
02.05.2010 6

I should get :

Serie A :
01.05.2010 1
02.05.2010 0
03.05.2010 3

Serie B:
01.05.2010 5
02.05.2010 6
03.05.2010 0

A: 

Not sure if this is elegant enough for you ;-) but since I like Linq, this is what I would have done (using your naming scheme):

public static IEnumerable<Serie> Equalize(
    this IEnumerable<Serie> series,
    int defaultCount)
{
    var allStamps = series
        .SelectMany(s => s.Data.Select(d => d.Stamp))
        .Distinct()
        .OrderBy(d => d)
        .ToList();

    return series.Select(serie => new Serie(
        serie.Name,
        allStamps.Select(d =>
            serie.Data.FirstOrDefault(stat => stat.Stamp == d)
            ??
            new Stat(d, defaultCount))
        ));
}

For this code to compile, your classes needs a couple of constructors:

public class Stat
{
    public Stat() {}

    public Stat(DateTime stamp, int count)
    {
        Stamp = stamp;
        Count = count;
    }

    public DateTime Stamp { get; set; }
    public int Count { get; set; }
}

public class Serie
{
    public Serie() {}

    public Serie(string name, IEnumerable<Stat> data)
    {
        Name = name;
        Data = new List<Stat>(data);
    }

    public string Name { get; set; }
    public List<Stat> Data { get; set; }
}

When calling series.Equalize(0) the code above will leave the original instances intact, and return a sequence of newly created Serie-instances with their Data padded with defaults.

Nothing magic about it. Just the sweetness of Linq... (and the null coalescing operator!)

I haven't tried this with loads and loads of data, so your milage may vary.

Lette
I ended up with a similar solution. I am actually not so sure if linq is really helpful here. It makes it a bit more concise, but how easy is it to understand what that chain of method is doing. Anyway, thanks for the answer!
Stephane
I fully agree with your concern. I'm thinking that the elegance might not be in the implementation of the `Equalize` method, but in the usage. How about sharing what you ended up with?
Lette