Overlapping Dates

CSharp · Console

/Program.cs

using System;
using System.Linq;
using System.Data;
using System.Collections.Generic;

public class Program
{
	public class Dates
	{
		public DateTime ActiveDate;
		public DateTime ExpireDate;
		public string Name;
	}

	public static void Main()
	{
		// original code.
		List<Dates> datesList = new List<Dates>();
		datesList.Add(new Dates{Name = "A", ActiveDate = new DateTime(2017, 8, 20), ExpireDate = new DateTime(2017, 8, 23)}); //Aug 20 - Aug 23
		datesList.Add(new Dates{Name = "B", ActiveDate = new DateTime(2017, 8, 20), ExpireDate = new DateTime(2017, 8, 22)}); //Aug 20 - Aug 22
		datesList.Add(new Dates{Name = "C", ActiveDate = new DateTime(2017, 8, 22, 23, 0, 0), ExpireDate = new DateTime(2017, 8, 26)}); //Aug 22 11pm - Aug 26
		datesList.Add(new Dates{Name = "D", ActiveDate = new DateTime(2017, 8, 20), ExpireDate = new DateTime(2017, 8, 23)}); //Aug 20 - Aug23
		
		// (took some of the old code out...)
		
		// extrapolate the actual arrays of days that belong to each "Dates" object
		var compareRanges = datesList.Select(d => GetDateRange(d)).ToList();
		
		// do a bit of LINQ here...
		var result = CompareDates(compareRanges, 3);
		
		// output the results.
		Console.WriteLine("Overlaps");
		foreach(var dt in result)
		{
			Console.WriteLine(dt.ToString("M/d/yyyy"));
		}
		
		var maxOverlap = GetLongestOverlap(compareRanges);

		Console.WriteLine();
		Console.WriteLine("Most overlaps: " + maxOverlap.Item2);
		foreach(var dt in maxOverlap.Item1)
		{
			Console.WriteLine(dt.ToString("M/d/yyyy"));
		}
	}

	// extrapolate a range of days based on the Dates object (evaluate start and end)
	private static DateTime[] GetDateRange(Dates dt)
	{
		// probably should put in some guard code here to validate the start/end dates!
		var start = dt.ActiveDate.Date;
		var end = dt.ExpireDate.Date;
		
		// we dont care about whether the date time is 11pm or other; we simply want to know if the day portions overlap
		// so let's build up a range of dates that let us do this.
		return Enumerable.Range(0, Convert.ToInt32((end.Date - start.Date).TotalDays) + 1)
			.Select(e => start.Date.AddDays(e)).ToArray();
	}
	
	// set the threshold to filter the overlapped dates...
	private static List<DateTime> CompareDates(List<DateTime[]> compareRanges, int overlapThreshold = 1)
	{
		// merge all the days into a grouped listing
		var grouped = compareRanges.SelectMany(r => r).GroupBy(d => d.Date);
		
		// filter the grouped list based on the overlap threshold, and pick out the appropriate dates
		var thresholdMatch = grouped.Where(g => g.Count() >= overlapThreshold)
			.Select(g => g.Key)
			.OrderBy(d => d)
			.ToList();
			
		return thresholdMatch;
	}	
	
	
	// which date in the ranges list has the most overlaps
	private static Tuple<List<DateTime>, int> GetLongestOverlap(List<DateTime[]> compareRanges)
	{
		var grouped = compareRanges.SelectMany(r => r).GroupBy(d => d.Date);
		var max = grouped.Max(g => g.Count());
		var maxMatch = grouped.Where(g => g.Count() == max)
			.Select(g => g.Key)
			.OrderBy(d => d)
			.ToList();
		
		return new Tuple<List<DateTime>, int>(maxMatch, max);
	}
}
;