首页 > 解决方案 > 为给定值查找最接近的值(顶部和底部)

问题描述

我有包含 Value 和 DateTime 的数据集以及另一个代表时间线的数据集。在这种情况下,时间线由相隔 15 分钟的舍入时间组成,但可以是 30 或 60 分钟......我想计算某些时间的线性插值。那些时间在另一个数据集中。

问题是如何找到最接近的时间和价值,即特定时间之间的时间?

这是我的实现:

class Program
{
    static void Main(string[] args)
    {
        List<Items> items = Items.GetItems();
        List<DateTime> dt = GenerateTimeLine(items[0].Time, items[items.Count - 1].Time, 15);

        DateTime X1 = items[0].Time;
        double Y1 = items[0].Value;

        DateTime X2 = items[1].Time;
        double Y2 = items[1].Value;


        DateTime X = dt[0];
        double newValue = LinearInterpolation(X.ToOADate(), X1.ToOADate(), X2.ToOADate(), Y1, Y2);
    }      

在上面,我知道开始时间和结束时间,但我想进行某种查询,每次查询 TimeLine 数据集并检查每次关闭时间,取值并插值

    static double LinearInterpolation(double X, double X1, double X2, double Y1, double Y2)
    {
        if ((X2 - X1) == 0)
        {
            return (Y1 + Y2) / 2;
        }
        else
        {
            return Y1 + (X - X1) * (Y2 - Y1) / (X2 - X1);
        }

    }

    private static List<DateTime> GenerateTimeLine(DateTime start, DateTime end, int interval)
    {
        List<DateTime> lstD = new List<DateTime>();            

        int res = interval / 2;
        int mod = (interval / 2) % 2;
        int sec = 0;

        if (interval == 1)
            sec = 30;
        else if (interval == 0)
            sec = 0;

        var tempStart = start.AddMinutes(interval).AddSeconds(sec);
        var tempEnd = end.AddMinutes(interval).AddSeconds(sec);
        DateTime st = new DateTime(tempStart.Year, tempStart.Month, tempStart.Day, tempStart.Hour, (tempStart.Minute / interval) * interval, 0);
        DateTime en = new DateTime(tempEnd.Year, tempEnd.Month, tempEnd.Day, tempEnd.Hour, (tempEnd.Minute / interval) * interval, 0);

        lstD.Add(st);

        while (st <= en)
        {
            st = st.AddMinutes(interval);
            lstD.Add(st);
        }

        return lstD;
    }

}

public class Items
{

    public double Value { get; set; }
    public DateTime Time { get; set; }

    public static List<Items> GetItems()
    {

        string input =
            "| 31         | 2019-03-10 20:39:15 |\n" +
            "| 12         | 2019-03-10 20:44:16 |\n" +
            "| 12         | 2019-03-10 20:51:16 |\n" +
            "| 33         | 2019-03-10 21:08:44 |\n" +
            "| 33         | 2019-03-10 21:09:16 |\n" +
            "| 11         | 2019-03-10 21:24:17 |\n" +
            "| 9          | 2019-03-10 21:36:18 |\n" +
            "| 14         | 2019-03-10 21:50:18 |\n" +
            "| 15         | 2019-03-10 22:09:19 |\n" +
            "| 16         | 2019-03-10 22:24:19 |\n" +
            "| 31         | 2019-03-10 22:39:20 |\n" +
            "| 3          | 2019-03-10 22:54:20 |\n" +
            "| 34         | 2019-03-10 23:09:21 |\n" +
            "| 10         | 2019-03-10 23:24:20 |\n" +
            "| 17         | 2019-03-10 23:39:22 |\n" +
            "| 18         | 2019-03-10 23:54:23";

        List<Items> items = new List<Items>();

        string line = "";
        StringReader reader = new StringReader(input);
        while ((line = reader.ReadLine()) != null)
        {
            string[] lineArray = line.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);

            Items newDate = new Items()
            {                   
                Value = int.Parse(lineArray[0]),
                Time = DateTime.Parse(lineArray[1])
            };

            items.Add(newDate);

        }

        return items;
    }

}

标签: c#linear-interpolation

解决方案


我终于想通了,如果有人遇到类似问题,这里是代码

static void Main(string[] args)
{                
  List<Dates> dates = Dates.GetDates();
  List<DateTime> lstTimeLine = GenerateTimeLine(dates[0].Time, dates[dates.Count-1].Time, 10);

  List<Dates> lstInterpolated = new List<Dates>();
  foreach(var itm in lstTimeLine)
  {
       var target = itm;
       Console.WriteLine("############################ X = " + itm);
       var smaller = dates.Last(x => x.Time <= target);
       var bigger = dates.FirstOrDefault(x => x.Time >= target);
       if (bigger == null)
           bigger = smaller;

       Console.WriteLine(smaller.ID + " " + smaller.Time + " " + smaller.Value);
       Console.WriteLine(bigger.ID + " " + bigger.Time + " " + bigger.Value); }
}

可能有更好的解决方案,但这完全满足我想要的。


推荐阅读