【问题标题】:Group by datatable value using linq使用 linq 按数据表值分组
【发布时间】:2013-05-16 13:37:46
【问题描述】:

我想使用 Linq 和 DataTable 来获得以下内容

数据表内容

periodstart periodend value
2013-01-01 2013-02-01 10
2013-02-02 2013-03-01 10
2013-03-02 2013-04-01 15
2013-04-02 2013-05-01 20
2013-05-02 2013-06-01 10
2013-06-02 2013-07-02 20

结果

2013-01-01 2013-03-01 10
2013-03-02 2013-04-01 15
2013-04-02 2013-05-01 20
2013-05-02 2013-06-01 10
2013-06-02 2013-07-02 20

基本上我想按值对周期进行分组,但如果中间的周期有不同的分组,也允许重复相同的值。

我想使用时间段的最小值和最大值来按值分组,但这会给我类似

2013-01-01 2013-06-01 10
2013-03-02 2013-04-01 15
2013-04-02 2013-07-02 20

这是不正确的。

如何解决这个问题?

【问题讨论】:

  • 您的经期是否总是连续且不重叠的?他们总是订购吗? (那么我们可以按“具有相同值的连续周期”分组吗?)
  • @JonSkeet 是的,期间是连续的且不重叠的!
  • 已经订购了?大概你可以单独做第一步......

标签: linq datatable group-by


【解决方案1】:

(添加一个单独的答案作为我现在删除的答案是错误的。)

听起来你只需要遍历所有行,保持一个组直到值部分发生变化,然后获取第一个元素的开头和最后一个元素的结尾。所以你可以做这样的事情作为扩展方法:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多