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
Реализации.
Сравнение Uid
s будет быстрее, чем сравнивать все содержимое каждого 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();