Linq计算时间差并选择最接近的时间差
Linq caculate time difference and choose closest one
我有这样一个对象列表:
+-------------+------------+---------------------+
| ID | Value | Time |
+-------------+------------+---------------------+
| 1 | 1 | 2019-03-07 20:05:35 |
| 2 | 2 | 2019-03-07 20:06:09 |
| 5 | 5 | 2019-03-07 20:11:27 |
| 7 | 1 | 2019-03-07 20:13:30 |
| 8 | 0 | 2019-03-07 20:13:41 |
| 7 | 1 | 2019-03-07 20:17:00 |
| 8 | 0 | 2019-03-07 20:22:20 |
| 7 | 1 | 2019-03-07 20:23:05 |
| 8 | 0 | 2019-03-07 20:27:35 |
| 7 | 1 | 2019-03-07 20:27:37 |
| 8 | 0 | 2019-03-07 20:28:01 |
| 7 | 1 | 2019-03-07 20:37:19 |
| 8 | 0 | 2019-03-07 20:37:27 |
| 7 | 1 | 2019-03-07 20:37:54 |
| 8 | 0 | 2019-03-07 20:40:11 |
| 7 | 1 | 2019-03-07 20:44:00 |
| 8 | 0 | 2019-03-07 20:45:00 |
| 7 | 1 | 2019-03-07 20:47:41 |
| 7 | 1 | 2019-03-07 20:48:43 |
| 7 | 1 | 2019-03-07 20:48:51 |
| 8 | 0 | 2019-03-07 20:51:11 |
| 8 | 0 | 2019-03-07 20:54:46 |
| 8 | 0 | 2019-03-07 20:55:36 |
+-------------+------------+---------------------+
如何select记录相隔15分钟但记录更接近下一次的时间?
结果应该是这样的:
+-------------+------------+---------------------+
| ID | Value | Time |
+-------------+------------+---------------------+
| 1 | 1 | 2019-03-07 20:05:35 |
| 8 | 0 | 2019-03-07 20:22:20 |
| 7 | 1 | 2019-03-07 20:37:19 |
| 8 | 0 | 2019-03-07 20:51:11 |
+-------------+------------+---------------------+
如果第一次是 20:05:35,接下来间隔 15 分钟是 20:22:20。最接近的时间是 20:22:20,因为它们之间的差异是 00:02:14,而 20:17:35 之间的差异是 00:02:25。有什么方法可以计算出差异并决定选择哪个更接近?
尝试以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication132
{
class Program
{
static void Main(string[] args)
{
List<Dates> dates = Dates.GetDates();
var results = dates.GroupBy(x => new DateTime(x.Time.Year, x.Time.Month, x.Time.Day, x.Time.Hour, 15 * (x.Time.Minute / 15), 0).AddMinutes(15))
.Select(x => x.OrderBy(y => x.Key.Subtract(y.Time)).First())
.ToList();
}
}
public class Dates
{
public int ID { get;set;}
public int Value { get;set;}
public DateTime Time { get;set;}
public static List<Dates> GetDates()
{
string input =
"| 1 | 1 | 2019-03-07 20:05:35 |\n" +
"| 2 | 2 | 2019-03-07 20:06:09 |\n" +
"| 5 | 5 | 2019-03-07 20:11:27 |\n" +
"| 7 | 1 | 2019-03-07 20:13:30 |\n" +
"| 8 | 0 | 2019-03-07 20:13:41 |\n" +
"| 7 | 1 | 2019-03-07 20:17:00 |\n" +
"| 8 | 0 | 2019-03-07 20:22:20 |\n" +
"| 7 | 1 | 2019-03-07 20:23:05 |\n" +
"| 8 | 0 | 2019-03-07 20:27:35 |\n" +
"| 7 | 1 | 2019-03-07 20:27:37 |\n" +
"| 8 | 0 | 2019-03-07 20:28:01 |\n" +
"| 7 | 1 | 2019-03-07 20:37:19 |\n" +
"| 8 | 0 | 2019-03-07 20:37:27 |\n" +
"| 7 | 1 | 2019-03-07 20:37:54 |\n" +
"| 8 | 0 | 2019-03-07 20:40:11 |\n" +
"| 7 | 1 | 2019-03-07 20:44:00 |\n" +
"| 8 | 0 | 2019-03-07 20:45:00 |\n" +
"| 7 | 1 | 2019-03-07 20:47:41 |\n" +
"| 7 | 1 | 2019-03-07 20:48:43 |\n" +
"| 7 | 1 | 2019-03-07 20:48:51 |\n" +
"| 8 | 0 | 2019-03-07 20:51:11 |\n" +
"| 8 | 0 | 2019-03-07 20:54:46 |\n" +
"| 8 | 0 | 2019-03-07 20:55:36";
List<Dates> dates = new List<Dates>();
string line = "";
StringReader reader = new StringReader(input);
while ((line = reader.ReadLine()) != null)
{
string[] lineArray = line.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
Dates newDate = new Dates()
{
ID = int.Parse(lineArray[0]),
Value = int.Parse(lineArray[1]),
Time = DateTime.Parse(lineArray[2])
};
dates.Add(newDate);
}
return dates;
}
}
}
代码将时间精确地移动到下一个间隔的 15 分钟间隔。时间的最小分辨率是 100ns(1 个滴答声)所以减去 1 个滴答声我认为是正确的解决方案
var results = dates.GroupBy(x => new DateTime(x.Time.Year, x.Time.Month, x.Time.Day, x.Time.Hour, 15 * (x.Time.Minute / 15), 0).AddMinutes(15).AddTicks(-1))
.Select(x => x.OrderBy(y => x.Key.Subtract(y.Time)).First())
.ToList();
要从开始时间开始按 15 分钟分组,请使用此
//tick is 100ns
const long TICKS_PER_15_MINUTES = 15 * 60 * 10000000L; //minutes, seconds, ticks
DateTime minTime = dates.OrderBy(x => x.Time).First().Time;
List<Dates> results = dates.GroupBy(x => (TICKS_PER_15_MINUTES * ((x.Time.Ticks - minTime.Ticks) / TICKS_PER_15_MINUTES) + TICKS_PER_15_MINUTES - 1))
.Select(x => x.OrderBy(y => x.Key - y.Time.Ticks).First())
.ToList();
最后,如果你想离最短时间最近 15 分钟
//tick is 100ns
const long TICKS_PER_15_MINUTES = 15 * 60 * 10000000L; //minutes, seconds, ticks
DateTime minTime = dates.OrderBy(x => x.Time).First().Time;
List<Dates> results = dates.GroupBy(x => ((x.Time.Ticks - minTime.Ticks) % TICKS_PER_15_MINUTES) < (TICKS_PER_15_MINUTES / 2)
? TICKS_PER_15_MINUTES * ((x.Time.Ticks - minTime.Ticks) / TICKS_PER_15_MINUTES)
: (TICKS_PER_15_MINUTES * ((x.Time.Ticks - minTime.Ticks) / TICKS_PER_15_MINUTES)) + TICKS_PER_15_MINUTES)
.Select(x => x.OrderBy(y => Math.Abs( x.Key - y.Time.Ticks)).First())
.ToList();
我有这样一个对象列表:
+-------------+------------+---------------------+
| ID | Value | Time |
+-------------+------------+---------------------+
| 1 | 1 | 2019-03-07 20:05:35 |
| 2 | 2 | 2019-03-07 20:06:09 |
| 5 | 5 | 2019-03-07 20:11:27 |
| 7 | 1 | 2019-03-07 20:13:30 |
| 8 | 0 | 2019-03-07 20:13:41 |
| 7 | 1 | 2019-03-07 20:17:00 |
| 8 | 0 | 2019-03-07 20:22:20 |
| 7 | 1 | 2019-03-07 20:23:05 |
| 8 | 0 | 2019-03-07 20:27:35 |
| 7 | 1 | 2019-03-07 20:27:37 |
| 8 | 0 | 2019-03-07 20:28:01 |
| 7 | 1 | 2019-03-07 20:37:19 |
| 8 | 0 | 2019-03-07 20:37:27 |
| 7 | 1 | 2019-03-07 20:37:54 |
| 8 | 0 | 2019-03-07 20:40:11 |
| 7 | 1 | 2019-03-07 20:44:00 |
| 8 | 0 | 2019-03-07 20:45:00 |
| 7 | 1 | 2019-03-07 20:47:41 |
| 7 | 1 | 2019-03-07 20:48:43 |
| 7 | 1 | 2019-03-07 20:48:51 |
| 8 | 0 | 2019-03-07 20:51:11 |
| 8 | 0 | 2019-03-07 20:54:46 |
| 8 | 0 | 2019-03-07 20:55:36 |
+-------------+------------+---------------------+
如何select记录相隔15分钟但记录更接近下一次的时间?
结果应该是这样的:
+-------------+------------+---------------------+
| ID | Value | Time |
+-------------+------------+---------------------+
| 1 | 1 | 2019-03-07 20:05:35 |
| 8 | 0 | 2019-03-07 20:22:20 |
| 7 | 1 | 2019-03-07 20:37:19 |
| 8 | 0 | 2019-03-07 20:51:11 |
+-------------+------------+---------------------+
如果第一次是 20:05:35,接下来间隔 15 分钟是 20:22:20。最接近的时间是 20:22:20,因为它们之间的差异是 00:02:14,而 20:17:35 之间的差异是 00:02:25。有什么方法可以计算出差异并决定选择哪个更接近?
尝试以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication132
{
class Program
{
static void Main(string[] args)
{
List<Dates> dates = Dates.GetDates();
var results = dates.GroupBy(x => new DateTime(x.Time.Year, x.Time.Month, x.Time.Day, x.Time.Hour, 15 * (x.Time.Minute / 15), 0).AddMinutes(15))
.Select(x => x.OrderBy(y => x.Key.Subtract(y.Time)).First())
.ToList();
}
}
public class Dates
{
public int ID { get;set;}
public int Value { get;set;}
public DateTime Time { get;set;}
public static List<Dates> GetDates()
{
string input =
"| 1 | 1 | 2019-03-07 20:05:35 |\n" +
"| 2 | 2 | 2019-03-07 20:06:09 |\n" +
"| 5 | 5 | 2019-03-07 20:11:27 |\n" +
"| 7 | 1 | 2019-03-07 20:13:30 |\n" +
"| 8 | 0 | 2019-03-07 20:13:41 |\n" +
"| 7 | 1 | 2019-03-07 20:17:00 |\n" +
"| 8 | 0 | 2019-03-07 20:22:20 |\n" +
"| 7 | 1 | 2019-03-07 20:23:05 |\n" +
"| 8 | 0 | 2019-03-07 20:27:35 |\n" +
"| 7 | 1 | 2019-03-07 20:27:37 |\n" +
"| 8 | 0 | 2019-03-07 20:28:01 |\n" +
"| 7 | 1 | 2019-03-07 20:37:19 |\n" +
"| 8 | 0 | 2019-03-07 20:37:27 |\n" +
"| 7 | 1 | 2019-03-07 20:37:54 |\n" +
"| 8 | 0 | 2019-03-07 20:40:11 |\n" +
"| 7 | 1 | 2019-03-07 20:44:00 |\n" +
"| 8 | 0 | 2019-03-07 20:45:00 |\n" +
"| 7 | 1 | 2019-03-07 20:47:41 |\n" +
"| 7 | 1 | 2019-03-07 20:48:43 |\n" +
"| 7 | 1 | 2019-03-07 20:48:51 |\n" +
"| 8 | 0 | 2019-03-07 20:51:11 |\n" +
"| 8 | 0 | 2019-03-07 20:54:46 |\n" +
"| 8 | 0 | 2019-03-07 20:55:36";
List<Dates> dates = new List<Dates>();
string line = "";
StringReader reader = new StringReader(input);
while ((line = reader.ReadLine()) != null)
{
string[] lineArray = line.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
Dates newDate = new Dates()
{
ID = int.Parse(lineArray[0]),
Value = int.Parse(lineArray[1]),
Time = DateTime.Parse(lineArray[2])
};
dates.Add(newDate);
}
return dates;
}
}
}
代码将时间精确地移动到下一个间隔的 15 分钟间隔。时间的最小分辨率是 100ns(1 个滴答声)所以减去 1 个滴答声我认为是正确的解决方案
var results = dates.GroupBy(x => new DateTime(x.Time.Year, x.Time.Month, x.Time.Day, x.Time.Hour, 15 * (x.Time.Minute / 15), 0).AddMinutes(15).AddTicks(-1))
.Select(x => x.OrderBy(y => x.Key.Subtract(y.Time)).First())
.ToList();
要从开始时间开始按 15 分钟分组,请使用此
//tick is 100ns
const long TICKS_PER_15_MINUTES = 15 * 60 * 10000000L; //minutes, seconds, ticks
DateTime minTime = dates.OrderBy(x => x.Time).First().Time;
List<Dates> results = dates.GroupBy(x => (TICKS_PER_15_MINUTES * ((x.Time.Ticks - minTime.Ticks) / TICKS_PER_15_MINUTES) + TICKS_PER_15_MINUTES - 1))
.Select(x => x.OrderBy(y => x.Key - y.Time.Ticks).First())
.ToList();
最后,如果你想离最短时间最近 15 分钟
//tick is 100ns
const long TICKS_PER_15_MINUTES = 15 * 60 * 10000000L; //minutes, seconds, ticks
DateTime minTime = dates.OrderBy(x => x.Time).First().Time;
List<Dates> results = dates.GroupBy(x => ((x.Time.Ticks - minTime.Ticks) % TICKS_PER_15_MINUTES) < (TICKS_PER_15_MINUTES / 2)
? TICKS_PER_15_MINUTES * ((x.Time.Ticks - minTime.Ticks) / TICKS_PER_15_MINUTES)
: (TICKS_PER_15_MINUTES * ((x.Time.Ticks - minTime.Ticks) / TICKS_PER_15_MINUTES)) + TICKS_PER_15_MINUTES)
.Select(x => x.OrderBy(y => Math.Abs( x.Key - y.Time.Ticks)).First())
.ToList();