7

我有以下模型:

public class Entry
{
    public int UseraccountId { get; set; }
    public int CompanyId { get; set; }
    public DateTime CreationDate { get; set; }
    public string Target { get; set; }
    public string Message { get; set; }
}

还有一个包含很多条目的列表:

List<Entry> entries = ... //get all entries.

例子:

分组前的示例

我现在希望将第 2 行和第 3 行分组,因为它们具有相同的 UserId、相同的 CompanyId、相同的目标和几乎(这是困难的部分),假设在 5 秒的范围内,相同的日期时间。

分组后,我的列表应如下所示:

在此处输入图像描述

这个问题有什么简单的方法吗?有什么建议吗?我打赌 Linq 会帮助我,但我不确定如何。

编辑: 谢谢大家的反馈。我决定更改设计并确保日期时间现在确实相同。所以现在用 linq 分组很容易。

4

3 回答 3

1

作为@dtb menitons,按“关闭”分组很困难,因为您最终可能会得到比您预期更大的“桶”。例如,如果您有 100 个彼此相隔 4 秒创建的条目,则将“下一个”项目 5 秒内的项目分组会将它们全部放在一个桶中!

但是,如果您想将创建日期四舍五入到最接近的值,例如 5 秒然后分组,您可以使用:

TimeSpan ts = new TimeSpan(0, 0, 5);  // 5 seconds
entries.GroupBy(i => new {
                          UserId = i.UserId, 
                          CompanyId = i.CompanyId, 
                          Target = i.Target, 
                          RoundedTime = DateTime.MinValue.AddTicks(
                                            (long)(Math.Round((decimal)i.CreationDate.Ticks / ts.Ticks) * ts.Ticks)
                                        ) ;
                          ))
       .Select(g => new {
                         UserId = g.Key.UserId, 
                         CompanyId = g.Key.CompanyId, 
                         Target = g.Key.Target, 
                         RoundedTime = g.Key.RoundedTime,
                         Message = string.Join(", ",g.Select(i=> i.Message).ToArray())
                        } );

这将按四舍五入到最接近的 5 秒的项目进行分组 - 相隔一秒的两个项目可能位于不同的存储桶中,但您不存在您声明的要求所具有的累积性问题。

于 2013-04-24T16:02:35.667 回答
0

这将给出 -5 秒的范围,但对于 CreationDate 上的完全匹配(聚类)算法,我猜它会困难得多。不过,你明白了。

List<Entry> entries = entries.GroupBy(a => a.UserId)
                             .ThenBy(a => a.CompanyId)
                             .ThenBy(a => a.CreationDate.AddSeconds(-5));
于 2013-04-24T15:46:48.587 回答
0

没有直接的答案,因为这取决于您认为匹配的内容。有简单和复杂的方法,以及介于两者之间的任何方法。您需要为此提出算法。一个简单的方法是减少秒数,只匹配到分钟,但这可能太长了。您可以编写一个方法将时间戳标准化为 5 或 10 秒,并按照已经建议的方式对其进行分组。

如果您想将 x 秒内的任意两条消息组合在一起,那么这种方法只会在大多数情况下有效。总会有那些值在范围内但落在截止值的任一侧。如果您对此感到满意并重视简单性,那么上述答案将起作用。

如果这不起作用并且您想跨人工截止进行分组,那么您将需要另一种方法。在这种情况下,一种简单的方法是使用 LINQ 按时间戳以外的所有内容进行分组。这将对您的数据进行初步分组。然后您可以遍历每个组并将每个时间值与同一组中的其他时间值进行比较,并确定它是否在您的范围内。然后手动抓取那些落在指定范围内的值并将它们组合在一起。

这有一个额外的边缘情况,您需要做出决定。如果您决定在 1 秒内分组,并且您有三个条目,其秒数是(简化的)1、2 和 3。1 和 2 在一秒内,2 和 3 也在一秒内,但 1 和 3 不是吨。你会根据 2 与其他人在一秒内对这些进行分组,还是将 1 和 2 分组,使 2 没有资格与 3 和 3 组合在一起。

您最终将获得一个解决方案,该解决方案的存储桶可以基于将值链接在一起而增长,或者基于创建的第一组而不是硬时间截止值来进行不同的人工截止值。困难时期要简单得多,因此除非您要拥有不断增长的存储桶,否则我建议您只使用标准化时间戳并对其进行分组。

你需要定义你的意思几乎并相应地计划。

于 2013-04-24T16:06:39.607 回答