我有以下型号:
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进行分组现在非常容易。
答案 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个单独使用。
你最终会得到一个解决方案,他们可以根据链接值一起增长,或者根据第一组创建而不是硬时间截止来实现不同的人工截止。困难时期要简单得多,所以除非你要增加桶,否则我建议你选择一个标准化的时间戳并对其进行分组。
你需要几乎定义你的意思并做出相应的计划。