Linq - 与之前元素的区别

时间:2014-03-14 21:12:50

标签: c# .net linq

有没有办法根据数据元素之间的差异对数据元素进行分组?

List<Message> messages = new List<Message>(); 

class Message
{
    private DateTime Date { get; set; }
    private string Text { get; set; }
}

消息日期中的示例数据:

14.3 2014 20:28:15
14.3 2014 20:32:17
14.3 2014 20:37:25
14.3 2014 22:38:43
14.3 2014 20:40:23
14.3 2014 20:42:07
14.3 2014 20:43:54
14.3 2014 20:52:26
14.3 2014 20:53:41
14.3 2014 20:55:37
14.3 2014 20:58:44

我需要LINQ这样的群组查询。如果没有记录六分钟,将启动一个新组。

Group 1
    14.3 2014 20:28:15
    14.3 2014 20:32:17

Group 2
    14.3 2014 20:37:25
    14.3 2014 20:38:43
    14.3 2014 20:40:23
    14.3 2014 20:42:07
    14.3 2014 20:43:54

Group 3
    14.3 2014 20:52:26
    14.3 2014 20:53:41
    14.3 2014 20:55:37
    14.3 2014 20:58:44

2 个答案:

答案 0 :(得分:1)

当然,我们可以创建自己的GroupWhile方法,让我们在条件满足时对项目进行分组:

var query = messages.GroupWhile((prev, current) => 
    prev.Date.AddMinutes(6) >= current.Date));

GroupWhile可以这样实现:

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;

        List<T> list = new List<T>() { iterator.Current };

        T previous = iterator.Current;

        while (iterator.MoveNext())
        {
            if (!predicate(previous, iterator.Current))
            {
                yield return list;
                list = new List<T>();
            }

            list.Add(iterator.Current);
            previous = iterator.Current;
        }
        yield return list;
    }
}

答案 1 :(得分:0)

如果您只想使用本机Linq方法执行此操作,则必须在linq查询之外保留一种状态变量。这不是好习惯,但这可行:

var groupNum = 0;
var prevDate = DateTime.MinValue;
var threshold = -TimeSpan.FromMinutes(6); // negative time makes things easier

var groups = messages.GroupBy(
    m => prevDate - (prevDate = m.Date) < threshold ? ++groupNum : groupNum);

同样,不建议在Linq查询之外跟踪状态变量,这种代码非常丑陋且令人困惑。但它确实有效。

我可能会在生产环境中使用更像Servy's answer的内容。