Получить ближайшее доступное значение из словаря - PullRequest
0 голосов
/ 26 октября 2018

У меня есть словарь
скажем

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 голосов
/ 26 октября 2018

Я думаю, что нашел решение для этого.

Step1: отсортировать (по убыванию) ключи меньше указанной даты и взять FirstOrDefault => PreviousKey
Step2: отсортировать (по убыванию) ключи больше указанной даты и принять FirstOrDefault =>NextKey

Шаг 3: Теперь проверьте разницу между ними
Шаг 4: Если (Date - PreviousKey)> (NextKey - Date), тогда возьмите NextKey иначе PreviousKey => FoundKey
Шаг 5: Теперь верните MyData [FoundKey]

0 голосов
/ 26 октября 2018

Вы можете просто поместить словарь в отсортированный словарь и выполнить бинарный поиск. Если ключ не существует, то элемент слева является ближайшим. Это не учитывает граничные сценарии, где ~ 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]];
    }
0 голосов
/ 26 октября 2018

Если вам нужно ближайшее значение, вам нужно перебрать словарь и взять наименьший промежуток времени, запомнить наименьшее и вернуть тот 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;
0 голосов
/ 26 октября 2018

Вы можете использовать приведенный ниже код,

Сортировать код по словарю по ключу (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;
        }

    }
0 голосов
/ 26 октября 2018

Вам понадобится упорядоченный словарь , и не только это, вам понадобится пользовательский компаратор для поиска ближайшей даты к ключу

См. Минимальный пример кода ниже

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...