I'm trying to get an average of flickering data that comes from a device that sends me a value periodically.
For instance, it sends me 5 values in a window of 1 minute, then the next value will come in one hour, and again one value in one minute, and the next value in several hours.
In terms of code, let's say that I have a List of Tuple<DateTime, int>. I've defined a threshold value that is, say, 15 minutes.
var flickeringThreshold = 15;
var flickeringList = new List<(DateTime, int)>(8);
// I'd like to regroup all these because the TimeSpan resulting of
// the substraction of two Dates Values ElementAt(index n+1) - ElementAt(index n)
// is under the threshold.
// By regroup I mean weight average the values and take the date
// when the flickering begins, but this not the issue here.
flickeringList.Add((new DateTime(2022, 3, 25, 9, 2, 5, DateTimeKind.Local), 3));
flickeringList.Add((new DateTime(2022, 3, 25, 9, 2, 10, DateTimeKind.Local), 5));
flickeringList.Add((new DateTime(2022, 3, 25, 9, 2, 15, DateTimeKind.Local), 3));
flickeringList.Add((new DateTime(2022, 3, 25, 9, 2, 20, DateTimeKind.Local), 5));
flickeringList.Add((new DateTime(2022, 3, 25, 9, 2, 25, DateTimeKind.Local), 3));
// This one lives on her own because the difference with the previous value in the list is over the threshold
flickeringList.Add((new DateTime(2022, 3, 25, 11, 4, 0, DateTimeKind.Local), 2));
// This one is alone no flickering
flickeringList.Add((new DateTime(2022, 3, 25, 11, 4, 30, DateTimeKind.Local), 3));
// This one lives on her own because the difference with the previous value in the list is over the threshold
flickeringList.Add((new DateTime(2022, 3, 25, 12, 7, 25, DateTimeKind.Local), 5));
My first approach to this problem was to use a for loop to compare elements. There would be a boolean value to signal that the flickering starts and stops...
My problem is that, with the example below, I can't seem to find a way to not take into account the 6th value when looping...
Pseudo code:
for (int i = 0; i < flickeringList.Count; i++)
{
var level = flickeringList[i].Item2;
var nextLevel = i < flickeringList.Count - 1 ? flickeringList[i + 1] : default;
DateTime forDurationStart = flickeringList[i].Item1;
DateTime forDurationEnd = i < flickeringList.Count - 1 ? (DateTime)flickeringList[i + 1].Item1 : default;
if ((forDurationEnd - forDurationStart).TotalMinutes < flickeringThreshold)
{
// Flickering detected
continue;
}
else
{
// We've gone past flickering...
}
}
How can I solve my problem ?
I've found a way to filter out the undesired row (using Lag from MoreLINQ) but lost the data to weight average in the process:
var filteredList = flickeringList
.OrderBy(e => e.Item1)
.Lag(1, (e, lag) => new
{
Event = e,
PreviousItem = lag,
})
.Where(x => x.PreviousItem == default || (x.Event.Item1 - x.PreviousItem.Item1).TotalMinutes > flickeringThreshold)
.Select(x => x.Event);