Вопрос

I have some dates which are currently stored as a list of strings.

For example:

List<string> dates = new List<string>();
dates.Add("1/10/14");
dates.Add("2/9/14");
dates.Add("1/15/14");
dates.Add("2/3/14");
dates.Add("2/15/14");

(The date is in mm/dd/yy format)

I will take a user's input (also in mm/dd/yy format), but as a string.

Now, I want to find the date in the array that is the next closest after the user input date.

For example, if the user enters "1/13/14", the output should be "1/15/14". If the user enters "2/5/14", then the next closest date is "2/9/14". But if the user enter a date that is later than the last date (say "3/1/14", it will STILL return the last date in the array which is "2/15/14")

I know at some point you have to convert to type DateTime, but I couldn't figure out the logic to find such date.

Это было полезно?

Решение

List<string> dates = new List<string>();
            dates.Add("1/10/14");
            dates.Add("2/9/14");
            dates.Add("1/15/14");
            dates.Add("2/3/14");
            dates.Add("2/15/14");

            var allDates = dates.Select(DateTime.Parse).OrderBy(d=>d).ToList();
            var inputDate = DateTime.Parse("1/13/14");

            var closestDate = inputDate >= allDates.Last()
                ? allDates.Last()
                : inputDate <= allDates.First()
                    ? allDates.First()
                    : allDates.First(d => d >= inputDate);

For now I'm just parsing strings, but you should handle it separately. This is simple plain LINQ, you can go fancy and do binary search as well.

Другие советы

Here is a solution that uses a Binary Search.

You need to have a list of DateTimes, no question about it. No point in keeping them as strings, parse them on the way into the list if you have to. You can use LINQ to convert all the elements in the list, but that's the only way you'll be able to compare dates with eachother.

Check out the page for BinarySearch to understand why I am using the bitwise operator on the return value.

//build list of random dates
Random r = new Random();
var dates = new List<DateTime>();
for (int i = 0; i < 10; i++)
{
    dates.Add(new DateTime(2014, r.Next(1,13), r.Next(1,28)));
}

//sort list (if you don't do this, you'll most likely get the wrong answer)
dates.Sort();

//get input
string input = "1/13/14";
DateTime inputDate = DateTime.Parse(input);

//find nearest
var result = dates.BinarySearch(inputDate);
DateTime nearest;

//get match or next in list.
if(result >= 0)
    nearest = dates[result];
else if (~result == dates.Count )
    nearest =dates.Last();
else
    nearest = dates[~result];

If you need to find the true closest, use this in place of the last if block.

//get match, or true nearest date in list
if(result >= 0)                   //date was found! Use that index.
    nearest = dates[result];
else if (~result == 0)            //date not found, smaller than any item in the list. use first index.
    nearest = dates.First();
else if(~result == dates.Count)   //date was not found, and is greater than all items. Use last index.
    nearest = dates.Last();
else                              //date not found, somewhere in the middle of the list. find the nearest date                              
{
    var daysAfter = dates[~result].Subtract(inputDate);      //date after input
    var daysBefore = inputDate.Subtract(dates[~result - 1]); //date before input
    if(daysAfter < daysBefore)
        nearest = dates[~result];
    else
        nearest = dates[~result - 1];
}
DateTime searchDate = new DateTime(2014,03,01);

var orderedDates = dates
.Select(d => DateTime.ParseExact(d, "M/d/yy", CultureInfo.InvariantCulture))
.OrderBy(d => d).ToList();

var result = orderedDates.FirstOrDefault(d => d > searchDate);
if (result == default(DateTime))
  result = orderedDates.Last();

Something like this?

List<string> dates   = YourListOfStringsHere() ; // list of strings in MM/dd/yyyy form.
DateTime desiredDate = new DateTime(2014,2,27) ;
DateTime foundDate   = dates
                       .Select( x => DateTime.ParseExact(x,"MM/dd/yyyy",CultureInfo.CurrentCulture))
                       .Where( x => x >= desiredDate.Date )
                       .Min()
                       ;

Why you'd be storing date/time values as a string is beyond me. When you load them, why not convert them? That way, they're easier to manipulate, you know you've got clean data. Everything becomes much simpler.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top