Jacob Huckins
Jacob Huckins

Reputation: 378

LINQ query to find objects in list with equal values for one of their properties

I am iterating through a list and looking for objects that have the same value for one of their properties. I need an IEnumerable of the unique values of the properties that overlap.

This was my original nested loop solution.

List<Event> eventsWithDatetimeCollisions = new List<Event>();
for (int i = 0; i < eventList.Count; i++)
{
    Event event1 = eventList[i];

    for (int j = i + 1; j < eventList.Count; j++) // for each event after event1 in the list
    {
        Event event2 = eventList[j];
    
        if (DateTime.Compare(event1.EventDateTime, event2.EventDateTime) == 0)
            eventsWithDatetimeCollisions.Add(event1);
    }
}

@NetMage pointed out a bug in my loop solution that if there are 3 events with the same time, the first will be added to the list twice and the second will be added once. A similar problem exists with my LINQ solution.

I came up with the following query that almost gives me the results I want but it has some duplicate values and I am wondering if it could be written better. I am manually checking that the events aren't the same, is there a way to avoid this? As I understand it, this query will compare every event to each event in the list including itself which results in a lot of extra comparisons.

var dateTimeCollisions = from event1 in eventList
                         from event2 in eventList
                         where event1 != event2   // I want to avoid this bit 
                               && DateTime.Compare(event1.EventDateTime, event2.EventDateTime) == 0
                         select event1;

This isn't something that needs to be optimized for speed, most of the time the list has less than 5 items in it and it's not getting executed regularly or at short intervals, I was just curious if there is a better way (more efficient, easier to read / write, etc).

Upvotes: 0

Views: 1450

Answers (2)

sidecus
sidecus

Reputation: 752

GroupBy might be a better option here - a bit more memory but much lower complexity.

eventList.GroupBy(x => x.EventDateTime).Where(g => g.Count() > 1)

Each group's key is the collision datetime, and value is the events which collide on that time.

Adding .Select(g => g.Key) will give you just the datetimes.

Upvotes: 5

NetMage
NetMage

Reputation: 26917

This will collect the first entry in eventList that has an equal EventDateTime later in the list.

var eventsWithDatetimeCollisions = eventList.GroupBy(e => e.EventDateTime)
                                            .Where(eg => eg.Count() > 1)
                                            .Select(eg => eg.First())
                                            .ToList();

Upvotes: 1

Related Questions