I am using Reactive library in my C# project to group data according to configured policies. All these data implement the following interface
public interface IPoint
{
object Value { get; }
DateTimeOffset Timestamp { get; }
}
One of the grouping policies I have to implement consists creating non-overlappable groups of a fixed time size, which looking at Reactive documentation could be achieved using Buffer(TimeSpan)
function. This is exactly what I need, but instead of using a runtime calculated timestamp I need to use the ones defined in the Timestamp
property of my objects.
I found this solution, which seems quite working:
public void Subscribe(Action<IEnumerable<IPoint>> callback)
{
long windowSizeTicks = TimeRange.Ticks; // TimeRange is my TimeSpan "buffer" size
dataPoints.GroupByUntil(x => x.Timestamp.Ticks / windowSizeTicks,
g => dataPoints.Where(x => x.Timestamp.Ticks / windowSizeTicks != g.Key))
.SelectMany(x => x.ToList())
.Subscribe(callback);
// dataPoints is ISubject<IPoint>
}
This solution just creates groups according to Ticks divisibility by TimeRange
, which doesn't work correctly if the first item is not divisible by it.
An example to explain what I mean: considering the following points
Value: 1, Timestamp: "2021-04-26T00:00:01"
Value: 2, Timestamp: "2021-04-26T00:00:02"
Value: 3, Timestamp: "2021-04-26T00:00:03"
Value: 4, Timestamp: "2021-04-26T00:00:04"
and a "buffer size" of 2 seconds, I am expecting them to be grouped as [1, 2], [3, 4]
, but instead I receive [1], [2, 3], [4]
. This happens because the grouping key is created considering the absolute time and not the difference from the starting of the data list.
I could save the timestamp of the first item and change the grouping function in this way, but I think (or at least I hope) there could be a better solution:
public void Subscribe(Action<IEnumerable<IPoint>> callback)
{
long windowSizeTicks = TimeRange.Ticks; // TimeRange is my TimeSpan "buffer" size
dataPoints.GroupByUntil(x => (x.Timestamp.Ticks - firstPoint.Timestamp.Ticks) / windowSizeTicks,
g => dataPoints.Where(x => (x.Timestamp.Ticks - firstPoint.Timestamp.Ticks) / windowSizeTicks != g.Key))
.SelectMany(x => x.ToList())
.Subscribe(callback);
// dataPoints is ISubject<IPoint>
}
I am a newbie at Reactive, so any helpful comment is welcome.
Thank you.