LINQ group by date - include empty days WITHOUT using join

后端 未结 3 759
天涯浪人
天涯浪人 2020-12-22 02:47

Using C#, NHibernate, NHibernate to LINQ. Using NHibernate to LINQ, I do not have the JOIN functionality. I can not use QueryOver either.

I have a LINQ query that co

3条回答
  •  死守一世寂寞
    2020-12-22 03:31

    There's a great way to do it by implementing an extension method for IEnumerable> (the type that is returned from GroupBy). In my humble opinion it's the best approach for a number of reasons:

    • Doesn't recalculate the result set being filled (.ToList() also accomplishes that, but at the price of eager evaluation),
    • Keeps lazy evaluation (deferred execution) of GroupBy,
    • One-liners friendly (can be chained inside a fluent LINQ query),
    • Generic, reusable,
    • Elegant, easy to read.

    Implementation

    public static IEnumerable> Fill(this IEnumerable> groups, IEnumerable filling)
    {
        List keys = filling.ToList();
    
        foreach (var g in groups)
        {
            if(keys.Contains(g.Key))
                keys.Remove(g.Key);
    
            yield return g;
        }
    
        foreach(var k in keys)
            yield return new EmptyGrouping(k);
    }
    
    
    
    class EmptyGrouping : List, IGrouping
    {
        public TKey Key { get; set; }
    
        public EmptyGrouping(TKey key)
        {
            this.Key = key;
        }
    }
    

    Sample usage

    Random rand = new Random();
    
    var results = Enumerable.Repeat(0, 5)                    // Give us five
        .Select(i => rand.Next(100))                         // Random numbers 0 - 99
        .GroupBy(r => r.Dump("Calculating group for:") / 10) // Group by tens (0, 10, 20, 30, 40...)
        .Fill(Enumerable.Range(0, 10))                       // Fill aby missing tens
        .OrderBy(g => g.Key);                                // Sort
    
    @"Anything above = eager evaluations.
    Anything below = lazy evaluations.".Dump();
    
    results.Dump();
    

    Sample output

    (Five integers on top are printed from inside the query when it's being evaluated. As you can see, there was only one calculation pass).

提交回复
热议问题