创建包含缺失键的分组

时间:2013-01-17 10:12:35

标签: c# linq grouping

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

目前我按日期对这些内容进行分组,这样我就可以获得至少有一个TT下的所有日期。

我想要的是,我可以将其用作查询的一部分,这将使我获得范围内的所有日期,无论是否存在具有给定日期的任何T <。 / p>

当前代码:

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之间。我想要的是它包含它们,没有元素。

我该怎么做?

2 个答案:

答案 0 :(得分:2)

您可以在分组前将所有日期的列表保留为联接调整,如下所示:

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);

答案 1 :(得分:1)

我已经将一个通用的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 });

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

这样做的好处是不需要对原始源进行多次查询来确定最小/最大值以生成密钥列表,然后再进一步查询以加入并获取数据。