ICal.net 日历比较



我一直在使用一个名为 ICal.net 的 nuget 包来加载 ics 文件以检查最近添加的事件。

我注意到在使用 IEnumerableExcept方法时,即使您可以看到添加了更多事件,也会错过一些事件。

我在活动中遇到了Uid属性,检查了一下,注意到它的独特性 - https://github.com/rianjs/ical.net/blob/5176d27ac243eb98a01157f2ed7ff3e2852b98eb/v2/ical.NET/Interfaces/Components/IUniqueComponent.cs#L14

我使用 Uid 为此编写了IEqualityComparer<IEvent>,但现在所有事件都被视为新事件。

只是想知道是否有人对我如何采用 2 个日历、比较事件并获得差异有任何建议?目前有 2000+ 个事件并且不断增加,因此试图保持其性能。

如果我理解正确的话,您有两个日历集合。一个表示具有多个 VEVENT 的 VCALENDAR,第二个表示稍后时间点的相同 VCALENDAR + VEVENT。通常,由于显而易见的原因,较晚的 VCALENDAR 比较早的日历具有更多的事件。你想比较两者以查看差异,即找到新事件。

  • 使用Uid可能就足够了,也可能不够;这取决于您的日历系统。虽然每个 UID 都应该是唯一的,但这取决于您的应用程序来保证。当 ical.net 创建事件时,它会执行Guid.NewGuid().ToString(),因此,如果您使用 ical.net 创建事件,它们应该是唯一的。谷歌日历和(我假设)其他流行的日历应用程序也提供了确定性的唯一Uid。
  • ical.net 认为Uid对于相等或哈希的目的并不重要。相反,它关注事件本身的组成。

如果您知道每个事件的 UID 都是唯一的,并且您没有兴趣将两个事件与不匹配的 Uid 进行比较,我会做这样的事情:

var eventIdSet = new HashSet<string>(StringComparison.OrdinalIgnoreCase);
var firstEventIds = firstCalendarCollection
.SelectMany(cc => cc.Event)
.Select(e => e.Uid);
eventIdSet.UnionWith(firstEventIds);
var secondEventIds = secondCalendarCollection
.SelectMany(cc => cc.Event)
.Select(e => e.Uid);
eventIdSet.ExceptWith(secondEventIds);

这应该为您提供第一个集合中存在的新日历 ID,而不是第二个集合。

如果你想比较事件内容,我会遵循相同的模式,停在Event对象上:

var firstSet = new HashSet<Event>();
var firstEvents = firstCalendarCollection.SelectMany(cc => cc.Event);
firstSet.UnionWith(firstEventIds);
var secondEvents = secondCalendarCollection.SelectMany(cc => cc.Event);
firstSet.ExceptWith(secondEvents);

这将做同样的事情,但正如我上面所说,事件 ID 被内部GetHashCodeEquals实现忽略。

单独比较Uid将比比较每个Event的全部内容更快。也就是说,除非这是一个繁忙的服务器应用程序,每秒必须多次执行此操作,否则这无关紧要。我们使用 ical.net,并对 800-1000 个日历事件执行这样的设置操作,在 WPF 应用程序中,计算时间是毫秒。除非在极端情况下,否则您可能不会注意到Uid比较和整个Event内容比较之间的差异。

编辑:我创建了一个维基页面:https://github.com/rianjs/ical.net/wiki/Comparing-collections-of-calendar-events

我建议使用 LINQ 执行 Where In 查询。

假设您有两个集合(已注册和可能是新的):

List<string> registeredIds = GetRegisteredComponentsUIds();
List<ComponentImplemenation> newEvents = GetNewEvents();
List<ComponentImplemenation> result = newEvents.Where(m => registeredIds.Contains(m.Uid))
.ToList();

最新更新