使用LINQ分组列表条目

时间:2013-04-24 15:38:06

标签: c# asp.net-mvc algorithm linq

我有以下型号:

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.

示例:

Example before grouping

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

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

enter image description here

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

修改 谢谢大家的反馈。 我决定改变设计并确保日期时间现在真的相同。因此,使用linq进行分组现在非常容易。

3 个答案:

答案 0 :(得分: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秒 - 相隔一秒的两个项目可能会在不同的存储桶中,但是你没有使用cummutativity的问题声明的要求有。

答案 1 :(得分:0)

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

List<Entry> entries = entries.GroupBy(a => a.UserId)
                             .ThenBy(a => a.CompanyId)
                             .ThenBy(a => a.CreationDate.AddSeconds(-5));

答案 2 :(得分:0)

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

如果要将任何两个x秒内的消息组合在一起,那么这种方法只会起作用。总会有那些在该范围内但落在截止值两侧的值。如果你对这个很简单,那么上面的答案就可以了。

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

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

你最终会得到一个解决方案,他们可以根据链接值一起增长,或者根据第一组创建而不是硬时间截止来实现不同的人工截止。困难时期要简单得多,所以除非你要增加桶,否则我建议你选择一个标准化的时间戳并对其进行分组。

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