There is an array of dates, each date is assigned a specific parameter value. The user enters the date and it is necessary to determine the value of the parameter, the date of which is closest to the entered date. The only thing that comes to mind is to use an array of tuples List<Tuple<T1, T2>> in which to store the parameter and the difference between dates (the date of the parameter and the entered date) and then sort and take the first value. Perhaps there is a more beautiful way? Thank.

  • one
    why sort all? You essentially just need the minimum. - pavel
  • Sort an array of dates, then find between what two elements the entered date will be, then choose the nearest date from two comparisons. The algorithmic complexity is the same ( O(N*log(N)) + O(log(n)) + O(1) = O(N*log(N)) ), but the logic, IMHO, will be simpler. - Yaant
  • one
    What sorting? What are O (N * log (N))? Just go through the list, O (n). - andreycha
  • @Yaant and if the entered date goes beyond the range? - e1s
  • @andreycha Yes, something brought me to unnecessary jungle. But if it is known that the source array is already sorted, then you can get by with the logarithm. :) - Yaant

3 answers 3

As you rightly noted, sorting is not needed. Faster will run through all the elements, on the move calculating the closest. Well, do not forget to bring the dates to UTC, for example, if you have them from different belts.

 var data = new Dictionary<DateTime, int>() { { DateTime.Now.AddDays(-2), -2 }, { DateTime.Now.AddDays(-1), -1 }, { DateTime.Now.AddDays(3), 3 }, }; var specifiedDate = DateTime.Now; var distances = data .Select(p => new { Distance = Math.Abs((specifiedDate - p.Key).Ticks), p.Value }); var distance = long.MaxValue; int closestParameter; foreach (var pair in distances) { if (pair.Distance < distance) { distance = pair.Distance; closestParameter = pair.Value; } } 

    Well, as an option, my favorite MinBy feature from the MoreLinq package:

     using MoreLinq; // ... var dict = new Dictionary<DateTime, string>() { [new DateTime(2016, 1, 1)] = "прошедший Новый Год", [new DateTime(2016, 12, 31)] = "будущий Новый Год", [new DateTime(2014, 1, 5)] = "давным-давно" }; var today = DateTime.Now; var closestValue = dict.MinBy(kvp => (kvp.Key - today).Duration()).Value; // -> будущий Новый Год 

      Use Linq, Luke ... :)

       var RawData = new List<DateTime> () { { DateTime.Now.AddDays(-2) }, { DateTime.Now.AddDays(-1) }, { DateTime.Now.AddDays(3) } } var specifiedDate = DateTime.Now; var minDistance = RawData.Min(n => (n - specifiedDate).Duration()); var minDate = RawData.Where(n => (n - specifiedDate).Duration() == minDistance).ToList(); 
      • one
        This is not quite true. This will give the minimum distance , but the date with the minimum distance is needed. - VladD
      • Ok, wrap in another filter. - Mirdin