开发者

find item in collection with closest date

if i have a collection of dates and values. I want to get the value that is either:

  1. Associated to the date in the collection
  2. if it doesn't exist, i 开发者_如何学运维want a linear interpolation between two points that are around the point i am looking for

ao, here is a simple example. If the collection is:

Date   Value  
1/1/2009   100  
1/1/2010   200  
1/1/2011   300  

if i am looking for 6/1/2010 i would get a value back 250. i can use any collection if one is better in solving than the other (dictionary, array, etc ..)


You can use the List type to hold the pairs, Sort them and use List.BinarySearch.

For instance you could have something like the following:

struct Pair
{
    public Pair(DateTime t, int v)
    {
        date = t;
        value = v;
    }
    public DateTime date;
    public int value;
}

    ....

    List<Pair> pairs = new List<Pair>();


    pairs.Add(new Pair(DateTime.Now, 100));
    pairs.Add(new Pair(DateTime.Now, 200));

    ....

    // Sort using the time.
    pairs.Sort(delegate(Pair pair1, Pair pair2) {
                           return  pair1.date.CompareTo( pair2.date);
                        }
              );

    // Do binary search.
    int index = pairs.BinarySearch(new Pair(dateToSearch, 0), 
                                   delegate(Pair pair1, Pair pair2) { 
                                       return pair1.date.CompareTo(pair2.date); 
                                   });

    if (index >= 0) {
        // Found the element!
        return pairs[index].value;
    }

    // If not found, List.BinarySearch returns the complement 
    // of the index where the element should have been.
    index = ~index;

    // This date search for is larger than any
    if (index == pairs.Count) {
        //
    }

    // The date searched is smaller than any in the list.
    if (index == 0) {
    }

    // Otherwise return average of elements at index and index-1.
    return (pairs[index-1].value + pairs[index].value)/2;

Of course the code is not the best possible, but you get the idea: use List, Sort it and then do BinarySearch.

Lookup MSDN for more information.

List: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

List.Sort: http://msdn.microsoft.com/en-us/library/3da4abas.aspx

List.BinarySearch: http://msdn.microsoft.com/en-us/library/3f90y839.aspx


A simple sorted (on date) list would be sufficient. Just find the last date (let's call it d1) that is less or equal than the date you are looking for (let's call that one d). The next date d2 will then be past d, assuming there are no duplicate dates.

Now if value v1 corresponds to d1 and v2 corresponds to d2 then the value you are looking for is v1 + (v2 - v1) / (d2 - d1) * (d - d1).


Given a "list of dates" and a "reference date", gets the "closest n numbers". C# code tested.

public class ClosestDate
{
    public void GetClosestDate(DateTime referenceDate, 
                                List<DateTime> listDates, int maxResults)
    {
        // final ordered date list
        List<DateTime> finalList = new List<DateTime>();

        DateTime selectedDate = DateTime.MaxValue;

        // loop number of results
        for (int i = 0; i < maxResults; i++)
        {
            // get next closest date
            int tempDistance = int.MaxValue;
            foreach (DateTime currentDate in listDates)
            {
                int currenDistance = this.DateDiff(currentDate, referenceDate);

                if (currenDistance < tempDistance)
                {
                    tempDistance = currenDistance;
                    selectedDate = currentDate;
                }
            }

            // build final list
            finalList.Add(selectedDate);
            // remove element from source list
            listDates.Remove(selectedDate);
        }

        // print results
        foreach (DateTime date in finalList)
        {
            Console.WriteLine(date.ToShortDateString());
        }

    }

    private int DateDiff(DateTime Date1, DateTime Date2)
    {
        TimeSpan time = Date1 - Date2;
        return Math.Abs(time.Days);
    }
}


You can try SortedDictionary. Do something like that:

int FindInterpolated(DateTime needle)
{
    try
    {
        DateTime lower = haystack.First(key => haystack[key] <= needle);
        DateTime upper = haystack.Last(key => haystack[key] >= needle);
        int v1 = haystack[lower];
        int v2 = haystack[upper];
        long ticksLower = lower.Ticks;
        long ticksUpper = upper.Ticks;
        return (v1 * ticksLower + v2 * ticksUpper) / (ticksLower + ticksUpper);
    }
    catch (InvalidOperationException)
    {
        // thrown if needle is out of range
        // (not between smallest and biggest keys in the haystack)
        ...
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜