131 lines
3.0 KiB
C#
131 lines
3.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Selector
|
|
{
|
|
public record struct CountSample {
|
|
public DateTime TimeStamp { get; set; }
|
|
public int Value { get; set; }
|
|
}
|
|
|
|
public static class Resampler
|
|
{
|
|
public static IEnumerable<CountSample> Resample(this IEnumerable<IListen> scrobbles, TimeSpan window)
|
|
{
|
|
var sortedScrobbles = scrobbles.OrderBy(s => s.Timestamp).ToList();
|
|
|
|
if (!sortedScrobbles.Any())
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
var sortedScrobblesIter = sortedScrobbles.GetEnumerator();
|
|
sortedScrobblesIter.MoveNext();
|
|
|
|
var earliest = sortedScrobbles.First().Timestamp;
|
|
var latest = sortedScrobbles.Last().Timestamp;
|
|
|
|
yield return new CountSample()
|
|
{
|
|
TimeStamp = earliest - (window / 2),
|
|
Value = 0
|
|
};
|
|
|
|
var enumeratorExhausted = false;
|
|
|
|
for (var windowStart = earliest; windowStart <= latest; windowStart += window)
|
|
{
|
|
var windowEnd = windowStart + window;
|
|
|
|
var count = 0;
|
|
var windowOverran = false;
|
|
|
|
while(!windowOverran && !enumeratorExhausted)
|
|
{
|
|
if (windowStart <= sortedScrobblesIter.Current.Timestamp)
|
|
{
|
|
if(sortedScrobblesIter.Current.Timestamp < windowEnd)
|
|
{
|
|
count++;
|
|
if (!sortedScrobblesIter.MoveNext())
|
|
{
|
|
enumeratorExhausted = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
windowOverran = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
yield return new CountSample()
|
|
{
|
|
TimeStamp = windowStart + (window / 2),
|
|
Value = count
|
|
};
|
|
}
|
|
}
|
|
|
|
public static IEnumerable<CountSample> ResampleByMonth(this IEnumerable<IListen> scrobbles)
|
|
{
|
|
var sortedScrobbles = scrobbles.OrderBy(s => s.Timestamp).ToList();
|
|
|
|
if (!sortedScrobbles.Any())
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
var sortedScrobblesIter = sortedScrobbles.GetEnumerator();
|
|
sortedScrobblesIter.MoveNext();
|
|
|
|
var earliest = sortedScrobbles.First().Timestamp;
|
|
var latest = sortedScrobbles.Last().Timestamp;
|
|
var latestPlusMonth = latest.AddMonths(1);
|
|
|
|
var periodStart = new DateTime(earliest.Year, earliest.Month, 1);
|
|
var periodEnd = new DateTime(latestPlusMonth.Year, latestPlusMonth.Month, 1);
|
|
|
|
for (var counter = periodStart; counter <= periodEnd; counter = counter.AddMonths(1))
|
|
{
|
|
var count = 0;
|
|
|
|
if (sortedScrobblesIter.Current is not null)
|
|
{
|
|
count++;
|
|
}
|
|
|
|
while (sortedScrobblesIter.MoveNext()
|
|
&& sortedScrobblesIter.Current.Timestamp.Year == counter.Year
|
|
&& sortedScrobblesIter.Current.Timestamp.Month == counter.Month)
|
|
{
|
|
count++;
|
|
}
|
|
|
|
yield return new CountSample()
|
|
{
|
|
TimeStamp = counter,
|
|
Value = count
|
|
};
|
|
}
|
|
}
|
|
|
|
public static IEnumerable<CountSample> CumulativeSum(this IEnumerable<CountSample> samples)
|
|
{
|
|
var sum = 0;
|
|
foreach(var sample in samples)
|
|
{
|
|
sum += sample.Value;
|
|
|
|
yield return new CountSample
|
|
{
|
|
TimeStamp = sample.TimeStamp,
|
|
Value = sum
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|