ICal.net Сравнение календарей

Я использовал пакет nuget под названием ICal.net для загрузки файлов ics для проверки событий, которые были недавно добавлены.

Я заметил при использовании IEnumerable Except метод для этого, что некоторые события пропущены, даже если вы видите, что было добавлено больше событий.

Я наткнулся на Uid свойство в событии, проверил его и заметил, что его уникальное - https://github.com/rianjs/ical.net/blob/5176d27ac243eb98a01157f2ed7ff3e2852b98eb/v2/ical.NET/Interfaces/Components/IUniqueComponent.cs#L14

Я написал IEqualityComparer<IEvent> для этого используется Uid, но теперь все события рассматриваются как новые события.

Было просто интересно, есть ли у кого-нибудь предложения о том, как я могу взять 2 календаря, сравнить события и получить различия? В настоящее время происходит более 2000 событий, поэтому мы стараемся поддерживать их производительность.

2 ответа

Решение

Если я вас правильно понимаю, у вас есть две коллекции календарей. Один представляет VCALENDAR с несколькими VEVENT, а второй представляет тот же VCALENDAR + VEVENT в более поздний момент времени. Часто более поздний VCALENDAR имеет больше событий, чем предыдущий календарь, по понятным причинам. И вы хотите сравнить два, чтобы увидеть разницу, то есть найти новые события.

  • С помощью Uid может быть достаточно, а может и не быть; это зависит от вашей календарной системы. Хотя каждый UID должен быть уникальным, это зависит от вашего приложения. Когда ical.net создает событие, он Guid.NewGuid().ToString(), так что если вы используете ical.net для создания событий, они должны быть уникальными. Календарь Google и (я полагаю) другие популярные приложения для составления календаря также предоставляют уникальные идентификаторы UID.
  • ical.net не считает Uid значимым для целей равенства или хеширования. Вместо этого он обращает внимание на состав самих событий.

Если вы знаете, что UID каждого события уникален, и вам не интересно сравнивать два события с непревзойденными Uids, я бы сделал что-то вроде этого:

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);

Это должно дать вам новые идентификаторы календаря, присутствующие в первой коллекции, но не во второй.

Если вы хотите сравнить содержимое события, я бы следовал той же схеме, останавливаясь на 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);

Это будет делать то же самое, но, как я уже сказал выше, идентификаторы событий игнорируются внутренним GetHashCode а также Equals Реализации.

Сравнение Uids будет быстрее, чем сравнивать все содержимое каждого Event, Тем не менее, если это не загруженное серверное приложение, которое должно делать это несколько раз в секунду, это не должно иметь значения. Мы используем ical.net и выполняем такие операции с 800-1000 календарными событиями, и это миллисекунды времени вычислений в приложении WPF. Вы, вероятно, не заметите разницу между Uid сравнения и в целом Event Сравнение содержания, за исключением экстремальных обстоятельств.

Изменить: Я создал страницу вики: https://github.com/rianjs/ical.net/wiki/Comparing-collections-of-calendar-events

Я бы порекомендовал сделать запрос Where In с LINQ.

при условии, что у вас есть две коллекции (зарегистрированные и, возможно, новые):

List<string> registeredIds = GetRegisteredComponentsUIds();

List<ComponentImplemenation> newEvents = GetNewEvents();

List<ComponentImplemenation> result = newEvents.Where(m => registeredIds.Contains(m.Uid))
                                               .ToList();
Другие вопросы по тегам