(添加一个单独的答案作为我现在删除的答案是错误的。)
听起来你只需要遍历所有行,保持一个组直到值部分发生变化,然后取第一个元素的开头和最后一个元素的结尾。所以你可以做这样的事情作为扩展方法:
public static IEnumerable<IEnumerable<T>> GroupByContiguous<T, TKey>
(this IEnumerable<T> source, Func<T, TKey> groupSelector)
{
List<T> currentGroup = new List<T>();
T groupKey = default(T);
// This could be passed in as a parameter
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
groupKey = groupSelector(iterator.Current);
currentGroup.Add(iterator.Current);
while (iterator.MoveNext())
{
var item = iterator.Current;
var key = groupSelector(item);
if (!comparer.Equals(groupKey, key))
{
yield return currentGroup.Select(x => x);
currentGroup = new List<T>();
groupKey = key;
}
currentGroup.Add(item);
}
}
// Trailing group
yield return currentGroup.Select(x => x);
}
然后将其用作:
var query = table.AsEnumerable()
.GroupByContiguous(row => row.Field<int>("value"))
.Select(g => new {
Value = g.Key,
EarliestStart = g.First().Field<DateTime>("periodstart"),
LatestEnd = g.Last().Field<DateTime>("periodend")
});