我想了解是否可以使用linq exp查找给定时间序列的所有开始和结束窗口(由开始和结束值界定)。 我知道可以通过常规循环来实现,但是我希望尽可能地扩大自己的知识。
数据存储在“ TagData”(List<TagData>
)的有序列表中
class TagData
{
public DateTime Timestamp { get; set; }
public string Tag { get; set; }
public double Value { get; set; }
}
最简单的方法是将数据内容完美地交替显示,例如:
timestamp | tag | value
2018-12-01 00:10:00.000 | extrg_01 | 1
2018-12-01 00:15:02.000 | extrg_01 | 0
2018-12-01 00:25:50.000 | extrg_01 | 1
2018-12-01 00:45:11.000 | extrg_01 | 0
此时,给定初始值= 1,最终值= 0,结果将是以下几行:
timestamp_start |timestamp_end | tag | nrOfSeconds
2018-12-01 00:10:00.000 |2018-12-01 00:15:02.000 | extrg_01 | 302
2018-12-01 00:25:50.000 |2018-12-01 00:45:01.000 | extrg_01 | 1161
但是也可能存在一些不需要考虑的“脏”数据:
timestamp | tag | value
2018-12-01 00:10:00.000 | extrg_01 | 1
2018-12-01 00:12:02.000 | extrg_01 | 1
2018-12-01 00:15:02.000 | extrg_01 | 0
2018-12-01 00:16:01.000 | extrg_01 | 0
2018-12-01 00:25:50.000 | extrg_01 | 1
2018-12-01 00:45:11.000 | extrg_01 | 0
在这种情况下,最终结果应与第一个示例相同,因为将不考虑定义的初始值(在这种情况下为= 1)之后的所有值,并且同样,仅将第一个最终值(在这种情况下为= 0)进行计算。
我忘记添加我要编辑的linq表达式以实现结果: 不幸的是,我无法理解如何在此.Zip中添加条件(如果可能的话)以查找特定值并遵守时间条件以始终查找下一个可用值。
var diffs = tagDataList.Skip(1)
.Zip(tagDataList,
(curr, prev) => new
{
CurrTag = curr.Tag,
CurrValue = curr.Value,
CurrDate = curr.Timestamp,
PrevDate = prev.Timestamp,
DiffToPrev = Math.Abs((curr.Timestamp - prev.Timestamp).TotalSeconds)
})
.ToList();
答案 0 :(得分:1)
可能有很多方法可以做到这一点。我会试一试:
我假设您希望单独处理不同的标签。这是我的方法:
我使用了以下测试数据:
var list = new List<TagData> {
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:09:00.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:10:00.000"), Tag = "extrg_01", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:10:00.000"), Tag = "extrg_02", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:12:02.000"), Tag = "extrg_01", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:15:02.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:16:01.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:15:02.000"), Tag = "extrg_02", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:25:50.000"), Tag = "extrg_01", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:45:11.000"), Tag = "extrg_01", Value = 0 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:25:50.000"), Tag = "extrg_02", Value = 1 },
new TagData { Timestamp = DateTime.Parse("2018-12-01 00:45:11.000"), Tag = "extrg_02", Value = 0 },
};
类定义:
class TagData
{
public DateTime Timestamp { get; set; }
public string Tag { get; set; }
public double Value { get; set; }
}
class TagSummary
{
public DateTime TimestampStart { get; set; }
public DateTime TimestampEnd { get; set; }
public string Tag { get; set; }
public TimeSpan TimeSpan => TimestampEnd - TimestampStart;
}
代码:
var summaries =
list.GroupBy(tagdata => tagdata.Tag) // Step (1)
.Select(group => // Step (2)
{
var data = group
.SkipWhile(tagdata => tagdata.Value == 0) // Step (2.1)
.Aggregate(new List<TagData>(), (acc, tagdata) => // Step (2.2)
{
if (acc.LastOrDefault()?.Value != tagdata.Value)
acc.Add(tagdata);
return acc;
});
var ones = data.Where(datatag => datatag.Value == 1);
var zeros = data.Where(datatag => datatag.Value == 0);
var result = ones.Zip(zeros, (startTag, endTag) => { // Step (2.3)
return new TagSummary { TimestampStart = startTag.Timestamp, TimestampEnd = endTag.Timestamp, Tag = startTag.Tag };
});
return result;
})
.SelectMany(x => x); // Step (3)
Console.WriteLine("timestamp_start | timestamp_end | tag | nrOfSeconds");
foreach (var summary in summaries)
Console.WriteLine($"{summary.TimestampStart:yyyy-MM-dd HH:mm:ss} | {summary.TimestampEnd:yyyy-MM-dd HH:mm:ss} | {summary.Tag,-8} | {summary.TimeSpan.TotalSeconds:0}");
输出与您指定的相同:
timestamp_start | timestamp_end | tag | nrOfSeconds
2018-12-01 00:10:00 | 2018-12-01 00:15:02 | extrg_01 | 302
2018-12-01 00:25:50 | 2018-12-01 00:45:11 | extrg_01 | 1161
2018-12-01 00:10:00 | 2018-12-01 00:15:02 | extrg_02 | 302
2018-12-01 00:25:50 | 2018-12-01 00:45:11 | extrg_02 | 1161
答案 1 :(得分:0)
我作为IEnumerator进行了操作,因此可以使用foreach。我添加了一个属性,以便代码返回开始时间和结束时间。
sing System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace ConsoleApplication94
{
class Program
{
static void Main(string[] args)
{
List<TagData> list = new List<TagData>() {
new TagData() { Timestamp = DateTime.Parse("2018-12-01 00:10:00.000"), Tag = "extrg_01", Value = 1},
new TagData() { Timestamp = DateTime.Parse("2018-12-01 00:12:02.000"), Tag = "extrg_01", Value = 1},
new TagData() { Timestamp = DateTime.Parse("2018-12-01 00:15:02.000"), Tag = "extrg_01", Value = 0},
new TagData() { Timestamp = DateTime.Parse("2018-12-01 00:16:01.000"), Tag = "extrg_01", Value = 0},
new TagData() { Timestamp = DateTime.Parse("2018-12-01 00:25:50.000"), Tag = "extrg_01", Value = 1},
new TagData() { Timestamp = DateTime.Parse("2018-12-01 00:45:11.000"), Tag = "extrg_01", Value = 0}
};
TagData data = new TagData(list);
foreach(TagData tagData in data)
{
DateTime start = tagData.Timestamp;
DateTime end = tagData.Endstamp;
double seconds = tagData.numberOfSeconds;
}
}
}
class TagData : IEnumerator<TagData>
{
public DateTime Timestamp { get; set; }
public string Tag { get; set; }
public double Value { get; set; }
public DateTime Endstamp { get; set; }
public double numberOfSeconds;
private List<TagData> listData;
private int curIndex;
private int endIndex;
private TagData curTagData;
public TagData() { }
public TagData(List<TagData> collection)
{
listData = collection;
curIndex = -1;
endIndex = -1;
curTagData = default(TagData);
}
public bool MoveNext()
{
if (curIndex != -1) curIndex = endIndex;
while ((++curIndex < listData.Count()) && (listData[curIndex].Value != 1)) { }
if (curIndex < listData.Count())
{
endIndex = curIndex;
while ((endIndex < listData.Count()) && (listData[endIndex].Value != 0)) endIndex++;
if (endIndex >= listData.Count()) return false;
listData[curIndex].Endstamp = listData[endIndex].Timestamp;
listData[curIndex].numberOfSeconds = (listData[curIndex].Endstamp - listData[curIndex].Timestamp).TotalSeconds;
}
else
{
return false;
}
curTagData = listData[curIndex];
return true;
}
public void Reset() { curIndex = -1; endIndex = -1; }
void IDisposable.Dispose() { }
public TagData Current
{
get { return curTagData; }
}
object IEnumerator.Current
{
get { return Current; }
}
public TagData GetEnumerator()
{
return new TagData(listData);
}
}
}
答案 2 :(得分:0)
基于 AndersCarstensen 的类和种子数据:
var z = list
.Where((t, index) => t.Value == 1 && list[index - 1].Value != 1)
.Select(t =>
new TagSummary
{
TimestampStart = t.Timestamp,
TimestampEnd = list.First(x => x.Timestamp > t.Timestamp && x.Value == 0).Timestamp,
Tag = t.Tag
}
);
/*
OUTPUT:
Start: 01.12.2018 0:10:00, End: 01.12.2018 0:15:02, Diff: 00:05:02, Tag: extrg_01
Start: 01.12.2018 0:25:50, End: 01.12.2018 0:45:11, Diff: 00:19:21, Tag: extrg_01
Start: 01.12.2018 0:25:50, End: 01.12.2018 0:45:11, Diff: 00:19:21, Tag: extrg_02
*/