创建包含缺失键的分组



我有一个IEnumerable<T>,它有一个Created字段,这是一个日期。
每个日期可以有多个T,有时在给定日期没有T

目前我按日期分组,这给了我至少有一个T的所有日期,以及它们下面的T

我想要的是,我可以使用的东西作为查询的一部分,将得到我的所有日期在一个范围内,不管是否有任何T 's与给定的日期。

当前代码:

var adjustments = DAL.GetAdjustmentsInDateRange(Start, End);
from adjustment in adjustments
group adjustment by adjustment.Created.Date into adjustmentsByDay
orderby adjustmentsByDay.Key descending
select ....

这里, adjustmentsByDay没有StartEnd之间的所有日期。我想要的是包含它们,而不是元素。

我该怎么做呢?

您可以在分组之前使用所有日期列表进行连接调整,如下所示:

var adjustments = DAL.GetAdjustmentsInDateRange(Start, End);
// Get all unique dates in time span
IEnumerable<DateTime> dates = GetAllDates(Start, End); 
var query = (from date in dates
                join adjustment in adjustments
                    on date.Date equals adjustment.Created.Date into a
                from adjustment in a.DefaultIfEmpty()
                select new {date.Date, adjustment}
                ).GroupBy(i=>i.Date).OrderBy(g=>g.Key);

我已经组合了一个通用的LINQ-to-objects扩展方法来将缺失的东西插入到序列中:

public static IEnumerable<T> InsertMissing<T, U>(this IEnumerable<T> source,
    Func<T, U> key, Func<U, U> increment, Func<U, T> create)
{
    bool first = true;
    U last = default(U);
    foreach (var ig in source)
    {
        U current = key(ig);
        if (first)
        {
            first = false;
            last = current;
            yield return ig;
            continue;
        }
        while (!(last = increment(last)).Equals(current))
        {
            yield return create(last);
        }
        yield return ig;
    }
}

您还需要自定义实现IGrouping:

class EmptyGrouping<K, E> : IGrouping<K, E> {
    public K Key { get; set; }
    public IEnumerator<E> GetEnumerator() {
        return Enumerable.Empty<E>().GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator() {
        return this.GetEnumerator(); 
    }
}

然后你需要在orderby之后结束你的查询,然后用这个调用,然后把你的select放在后面:

var allGroups = query.InsertMissing(
    // Key selector
    g => g.Key,
    // Get next desired key from current key
    d => d.AddDays(-1),
    // Create item for missing key
    d => new EmptyGrouping<DateTime,YourAdjustmentType>{ Key = d });

这个乱套,如果你的钥匙没有顺序,或者如果其中一个没有落在正确的位置(例如,在你的情况下,不是在午夜)。

这样做的优点是不需要在原始源上进行多次查询来确定最小/最大值以生成键列表,然后再进行进一步查询以连接并获取数据。

相关内容

  • 没有找到相关文章