Reputation: 820
I've been using a nuget package called ICal.net to load ics files to check for events that have recently been added.
I've noticed while using the IEnumerable Except
method for this that some events are missed even though you can see that more events have been added.
I came across the Uid
property in the Event, checked it out and noticed that its unique - https://github.com/rianjs/ical.net/blob/5176d27ac243eb98a01157f2ed7ff3e2852b98eb/v2/ical.NET/Interfaces/Components/IUniqueComponent.cs#L14
I wrote a IEqualityComparer<IEvent>
for this using the Uid but now all events are being seen as new events.
Was just wondering if anyone had any suggestions on how I can take 2 calendars, compare the events and get the differences? Currently there is 2000+ events and increasing so trying to keep it performant.
Upvotes: 1
Views: 2099
Reputation: 7944
If I understand you correctly, you have two collections of calendars. One represents a VCALENDAR with multiple VEVENTs, and the second represents the same VCALENDAR + VEVENTs at a later point in time. Often the later VCALENDAR has more events than the earlier calendar, for obvious reasons. And you want to compare the two to see the difference, i.e., find the new events.
Uid
might be sufficient, and it might not be; it depends on your calendaring system. While each UID should be unique, that's up to your application to guarantee. When ical.net creates an event, it does a Guid.NewGuid().ToString()
, so if you're using ical.net to create events, they should be unique. Google Calendar and (I assume) other popular calendaring applications also provide deterministically unique Uids.Uid
significant for the purposes of equality or hashing. Instead, it pays attention to the composition of the events themselves.If you know that each event's UID is unique, and you have no interest in comparing two events with unmatched Uids, I would do something like this:
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);
That should give you the new calendar ids present in the first collection, but not the second.
If you want to compare event contents, I would do follow the same pattern, stopping at the Event
object:
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);
This will do the same thing, but as I said above, event ids are ignored by the internal GetHashCode
and Equals
implementations.
Comparing Uid
s alone will be faster than comparing the entire contents of each Event
. That said, unless this is a busy server application that has to do this multiple times per second, it shouldn't matter. We are using ical.net, and doing set operations like this with 800-1000 calendar events, and it's milliseconds of compute time in a WPF application. You probably wouldn't notice the difference between the Uid
comparisons and the whole Event
content comparison except under extreme circumstances.
Edit: I've created a wiki page: https://github.com/rianjs/ical.net/wiki/Comparing-collections-of-calendar-events
Upvotes: 0
Reputation: 989
I would recommend doing a Where In query with LINQ.
assuming you have two collections (registered and possibly new):
List<string> registeredIds = GetRegisteredComponentsUIds();
List<ComponentImplemenation> newEvents = GetNewEvents();
List<ComponentImplemenation> result = newEvents.Where(m => registeredIds.Contains(m.Uid))
.ToList();
Upvotes: 0