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查询组。如果6分钟内没有记录,将开始一个新的分组。

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

当然,我们可以创建自己的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;
    }
}

如果你想只使用本地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的的答案。

相关内容

  • 没有找到相关文章

最新更新