从字典中获取最接近的可用值

时间:2018-10-26 04:50:15

标签: c# dictionary

我正在字典

Dictionary<DateTime, double> MyData  

现在我想从字典中获取值。
但是,如果密钥不存在,那么我需要取最接近的值。

让我们调用函数

double GetMyData(Dictionary<DateTime, double> MyData, DateTime Date)  
    {  
      if(MyData.ContainsKey(Date)  
      {
          return MyData[Date];
      }  
      else  
      {  
          //return the nearest available value.  
          // if Date is '2018-01-01', then try to look for next date,  
          // It can be '2018-01-02' or even '2017-12-31'  
          // Here aim is to get the nearest available value.
      }  
    } 

编辑:
样本数据:

MyData['2018-01-01'] = 420.0;  
MyData['2018-02-01'] = 220.0;  
MyData['2018-03-01'] = 320.0;  
MyData['2018-05-01'] = 210.0;  
MyData['2018-06-01'] = 220.0;   
MyData['2018-07-01'] = 230.0;  
MyData['2018-08-01'] = 240.0;

此处密钥'2018-04-01'不可用,
因此,我需要任何最接近的可用值。
它可以是'2018-03-01'或'2018-05-01'的值
现在希望它已清除。
而且请不要冒犯,英语不是我的母语。

5 个答案:

答案 0 :(得分:2)

您将需要一个有序词典,不仅如此,还需要一个自定义比较器来找到最接近该键的日期

请参阅下面的最小示例代码

void Main()
{
    OrderedDictionaryByDateTime<double> data = new OrderedDictionaryByDateTime<double>();
    data.Add(DateTime.Now, 1.1);
    data.Add(DateTime.Now.AddDays(-1), 1.2);
    data.Add(DateTime.Now.AddDays(2), 1.3);
    data.Add(DateTime.Now.AddDays(3), 1.4);
    data.Add(DateTime.Now.AddDays(-5), 1.5);

    var tomorrow = DateTime.Now.AddDays(1);
    var oneHourBefore = DateTime.Now.AddHours(-1);
    var theDayAfterTomorrow = DateTime.Now.AddDays(2);
    var yesterday = DateTime.Now.AddDays(-1);
    var fourDaysInThePast = DateTime.Now.AddDays(-4);

    data.GetValueClosestToTheDateTimeKey(tomorrow); // should be 1.1
    data.GetValueClosestToTheDateTimeKey(oneHourBefore); // should be 1.1
    data.GetValueClosestToTheDateTimeKey(yesterday); // should be 1.2
    data.GetValueClosestToTheDateTimeKey(theDayAfterTomorrow); // should be 1.3
    data.GetValueClosestToTheDateTimeKey(fourDaysInThePast); // should be 1.5
}

public class OrderedDictionaryByDateTime<TValue> : List<KeyValuePair<DateTime, TValue>>
{
    private readonly Dictionary<DateTime, int> _dictionary = new Dictionary<DateTime, int>();

    public void Add(DateTime key, TValue value)
    {
        Add(new KeyValuePair<DateTime, TValue>(key, value));
        _dictionary.Add(key, Count - 1);
    }

    public TValue Get(DateTime key)
    {
        var idx = _dictionary[key];
        return this[idx].Value;
    }

    public TValue GetValueClosestToTheDateTimeKey(DateTime key)
    {
        var closestDate = _dictionary.Keys.OrderBy(t => Math.Abs((t - key).Ticks)).First();

        return Get(closestDate);
    }
}

答案 1 :(得分:1)

您只需将字典放入经过排序的字典中,然后进行二进制搜索。     如果该键不存在,则左侧的项目是最接近的项目。     这不适用于〜index-1变为-1等的边界情况...

public static double GetMyData(Dictionary<DateTime, double> MyData, DateTime Date)
{
        var sorted = new SortedDictionary<DateTime, double>(MyData);

        var keys = new List<DateTime>(sorted.Keys);
        var index = keys.BinarySearch(Date);

        if (index >= 0) return sorted[keys[index]];

        else
            return sorted[keys[~index - 1]];
    }

答案 2 :(得分:0)

如果您需要最接近的值,则需要遍历字典并以最小的时间跨度记住最小的时间并返回该DateTime。

TimeSpan timeSpan=DateTime.MinValue-DateTime.MaxValue;
double returnDate;
foreach(var key in MyData.Keys)
{
  if(key<Date)
  {
    var dif = Date-key;
    if(dif<timeSpan)
    {
     timeSpan=dif;
     returnDate=MyData[key];
    }
  }
  else
  {
    var dif = key-Date;
    if(dif<timeSpan)
    {
     timeSpan=dif;
     returnDate=MyData[key];
    }
  }
 }
  return returnDate;

答案 3 :(得分:0)

您可以在下面使用代码,

按键(DateTime)对字典排序,并查找GreaterOrEqual日期值。如果存在有效记录,则返回第一个值,否则返回-1

    public double? getData(Dictionary<DateTime,double> source, DateTime date) 
    {
        if (source.Where(x => x.Key >= date).OrderBy(x => x.Key).Count() > 0)
            return source.Where(x => x.Key >= date).OrderBy(x => x.Key).FirstOrDefault().Value;
        else
            return -1;
    }

如果要获取最接近的值(向上或向下),可以使用下面的代码,

    public double? getData(Dictionary<DateTime,double> source, DateTime date) 
    {
        DateTime up = source.Where(x => x.Key >= date).OrderBy(x => x.Key).Count() > 0 ? source.Where(x => x.Key >= date).OrderBy(x => x.Key).FirstOrDefault().Key : DateTime.MinValue;
        DateTime down = source.Where(x => x.Key <= date).OrderByDescending(x => x.Key).Count() > 0 ? source.Where(x => x.Key <= date).OrderByDescending(x => x.Key).FirstOrDefault().Key : DateTime.MinValue;

        long up_difference = -1;
        long down_difference = -1;

        if (up != DateTime.MinValue)
            up_difference = up.Ticks - date.Ticks;

        if (down != DateTime.MinValue)
            down_difference = date.Ticks - down.Ticks;

        // There are no values upper or higher
        if (up_difference == -1 && down_difference == -1)
            return null;
        else if (up_difference != -1 && down_difference != -1)
        {
            if(up_difference < down_difference)
                return source.Where(x => x.Key == up).FirstOrDefault().Value;
            else
                return source.Where(x => x.Key == down).FirstOrDefault().Value;
        }
        else if(up_difference != -1)
        {
            return source.Where(x => x.Key == up).FirstOrDefault().Value;
        }
        else
        {
            return source.Where(x => x.Key == down).FirstOrDefault().Value;
        }

    }

答案 4 :(得分:0)

我想我已经找到了解决方案。

Step1:对小于给定日期的键进行排序(降序),并采用FirstOrDefault => PreviousKey
步骤2:对大于给定日期的键进行排序(降序),并采用FirstOrDefault => NextKey

Step3:现在检查它们之间的区别
步骤4:如果(Date-PreviousKey)>(NextKey-Date),则取NextKey否则PreviousKey => FoundKey
步骤5:现在,返回MyData [FoundKey]