创建包含丢失键的分组
我有一个IEnumerable<T>
,它有一个Created
字段,这是一个日期。
每个日期可能有多个T
,有时在给定日期没有T
。创建包含丢失键的分组
当前我将这些日期按照日期分组,这些日期至少包含一个日期,其中包含至少一个T
和T
。
但是我想要的是,我可以将其用作查询的一部分,这将使我获得某个范围内的所有日期,而不管在给定日期是否有任何T
。
目前代码:
var adjustments = DAL.GetAdjustmentsInDateRange(Start, End);
from adjustment in adjustments
group adjustment by adjustment.Created.Date into adjustmentsByDay
orderby adjustmentsByDay.Key descending
select ....
这里,adjustmentsByDay
没有Start
和End
之间的所有日期。我想要的是它包含它们,没有任何元素。
我该怎么做?
我已经把通用的LINQ到对象扩展方法插入缺失的东西放进顺序:
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 });
这将就会失控,如果你的钥匙是没有顺序的,或者其中一个不在正确的位置(例如,在你的情况下,不是在午夜)。
这样做的好处是不需要对原始源进行多个查询来确定最小/最大值以生成密钥列表,然后再进一步查询以加入并获取数据。
你可以离开分组加盟之前所有日期的列表的调整,像这样:
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);
这看起来不错,但此刻我在群组中按行发生错误,因为'adjust'为'null'(我已经离开那条线并且在相同的位置)。 –
对不起,如果有语法错误。参考Linq 101,左外连接是最后一个例子:http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b –
我现在更新了我的答案,但是组和顺序是在方法中语法而不是查询语法。这个解决方案适用于我,假设你可以首先创建一个所有日期列表,包括'开始'和'结束' –
好!喜欢查询扩展。 –