score:1

Accepted answer

I will propose 2 solutions for your problem, depend on the length of your list one will be better.

Initialize :

var myList = new List<DataRecord>
{
    new DataRecord
    {
        MeasurementDate = new DateTime(2019, 1, 31, 11, 50, 0)
    },
    new DataRecord
    {
        MeasurementDate = new DateTime(2019, 1, 31, 17, 21, 0)
    },
    new DataRecord
    {
        MeasurementDate = new DateTime(2019, 1, 31, 17, 59, 0)
    },
    new DataRecord
    {
        MeasurementDate = new DateTime(2019, 1, 31, 10, 54, 0)
    },
    new DataRecord
    {
        MeasurementDate = new DateTime(2019, 1, 31, 11, 54, 0)
    },
};

List<DataRecord> result = new List<DataRecord>();

Solution 1 :

var minimumMinutes = myList.Min(x => x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute);
var maximumMinutes = myList.Max(x => x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute);

for (int minutes = minimumMinutes; minutes < maximumMinutes; minutes++)
{
    var list = myList.Where(x =>
        x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute <= minutes + 60 &&
        x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute >= minutes);

    if (result.Count < list.Count())
    {
        result = list.ToList();
    }
}

Solution 2 :

foreach (var dataRecord in myList)
{
    var minutes = dataRecord.MeasurementDate.Hour * 60 + dataRecord.MeasurementDate.Minute;
    var before = myList.Where(x =>
        x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute >= minutes - 60 &&
        x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute <= minutes).ToList();
    var after = myList.Where(x =>
        x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute <= minutes + 60 &&
        x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute >= minutes).ToList();

    if (before.Count > result.Count ||
        after.Count > result.Count)
    {
        result = before.Count > after.Count ? before.ToList() : after.ToList();
    }
}

score:1

As I mentioned in comments this code is not performance efficient, but this will do the trick.

// DummyData
List<DateTime> dates = new List<DateTime>
{
    DateTime.Parse("2019/01/31 11:50"),
    DateTime.Parse("2019/02/02 17:21"),
    DateTime.Parse("2019/03/01 17:59"),
    DateTime.Parse("2019/03/12 10:54"),
    DateTime.Parse("2019/05/28 11:15"),
};

// Storage for final Output
List<DateTime> finalOp = new List<DateTime>();

// Main logic goes here
// foreach Hour in list we will compare that with every other Hour in list
// and it is in 1 hour range we will add it to list
foreach (DateTime dateTime in dates)
{
    List<DateTime> temp = new List<DateTime>();
    foreach (DateTime innerDateTime in dates)
    {
        // find the difference between two hours
        var timeSpan = dateTime.TimeOfDay - innerDateTime.TimeOfDay;

        // add it to same list if we have +/- 1 Hour difference
        if (timeSpan.TotalHours <= 1 && timeSpan.TotalHours >= -1)
        {
            temp.Add(innerDateTime);
        }

    }

    // once we have final group for date we will check if this has maximum number of common dates around
    // if so replace it with previous choice
    if (finalOp.Count < temp.Count)
    {
        finalOp = temp;
    }
}

// print the results
foreach (var data in finalOp)
{
    Console.WriteLine(data.ToShortTimeString());
}

score:0

For the 10,000 items of myList collection this solution can be fast:

private static List<DataRecord> Get(List<DataRecord> myList)
    {
        var ordered = myList.OrderBy(x => x.MeasurementDate.TimeOfDay).ToList();
        int i = 0;
        int count = myList.Count();
        var temp =
            (from s in ordered
            let index = ++i
            let next = ordered.ElementAtOrDefault(index != count ? index : 0)
            select new
            {
                Cur = s.MeasurementDate,
                Diff = index != count
                    ? (next.MeasurementDate.TimeOfDay - s.MeasurementDate.TimeOfDay).TotalMinutes
                    : 24 * 60 - (ordered.ElementAtOrDefault(count - 1).MeasurementDate.TimeOfDay - ordered.ElementAtOrDefault(0).MeasurementDate.TimeOfDay).TotalMinutes
            }).ToList();

        Dictionary<int, int> dict = new Dictionary<int, int>();
        count = 0;
        double minutes = 0;
        for (int index = 0; index < temp.Count(); index++)
        {
            for (int j = index; j < temp.Count(); j++)
            {
                minutes += temp[j].Diff;
                if (minutes > 60)
                {
                    dict.Add(index, count);
                    count = 0;
                    minutes = 0;
                    break;
                }
                else
                {
                    count++;
                }
            }
        }

        var max = dict.First(d => d.Value == dict.Values.Max());
        var finalResult = ordered.Skip(max.Key).Take(max.Value + 1).ToList();
        return finalResult;
    }

Please note it returns ordered results.


Related Articles