1-dimensional data
auto index = [1, 2, 3, 4]; auto data = [2.1, 3.4, 5.6, 7.8]; auto series = index.series(data); const cseries = series; assert(series.contains(2)); assert( ()@trusted{ return (2 in series) is &data[1]; }() ); assert(!series.contains(5)); assert( ()@trusted{ return (5 in series) is null; }() ); assert(series.lowerBound(2) == series[0 .. 1]); assert(series.upperBound(2) == series[2 .. $]); assert(cseries.lowerBound(2) == cseries[0 .. 1]); assert(cseries.upperBound(2) == cseries[2 .. $]); // slicing type deduction for const / immutable series static assert(is(typeof(series[]) == Series!(int*, double*))); static assert(is(typeof(cseries[]) == Series!(const(int)*, const(double)*))); static assert(is(typeof((cast(immutable) series)[]) == Series!(immutable(int)*, immutable(double)*))); /// slicing auto seriesSlice = series[1 .. $ - 1]; assert(seriesSlice.index == index[1 .. $ - 1]); assert(seriesSlice.data == data[1 .. $ - 1]); static assert(is(typeof(series) == typeof(seriesSlice))); /// indexing assert(series[1] == observation(2, 3.4)); /// range primitives assert(series.length == 4); assert(series.front == observation(1, 2.1)); series.popFront; assert(series.front == observation(2, 3.4)); series.popBackN(10); assert(series.empty);
2-dimensional data
import mir.date: Date; import mir.ndslice.topology: canonical, iota; size_t row_length = 5; auto index = [ Date(2017, 01, 01), Date(2017, 02, 01), Date(2017, 03, 01), Date(2017, 04, 01)]; // 1, 2, 3, 4, 5 // 6, 7, 8, 9, 10 // 11, 12, 13, 14, 15 // 16, 17, 18, 19, 20 auto data = iota!int([index.length, row_length], 1); // canonical and universal ndslices are more flexible then contiguous auto series = index.series(data.canonical); /// slicing auto seriesSlice = series[1 .. $ - 1, 2 .. 4]; assert(seriesSlice.index == index[1 .. $ - 1]); assert(seriesSlice.data == data[1 .. $ - 1, 2 .. 4]); static if (kindOf!(typeof(series.data)) != Contiguous) static assert(is(typeof(series) == typeof(seriesSlice))); /// indexing assert(series[1, 4] == observation(Date(2017, 02, 01), 10)); assert(series[2] == observation(Date(2017, 03, 01), iota!int([row_length], 11))); /// range primitives assert(series.length == 4); assert(series.length!1 == 5); series.popFront!1; assert(series.length!1 == 4);
Construct from null
import mir.series; alias Map = Series!(string*, double*); Map a = null; auto b = Map(null); assert(a.empty); assert(b.empty); auto fun(Map a = null) { }
import mir.series: series, sort; auto s = ["b", "a"].series([9, 8]).sort; import mir.format : text; assert(s.text == `{ index: [a, b], data: [8, 9] }`);
Plain index series data structure.
*.index[i]/*.key[i]/*.time corresponds to *.data[i]/*.value.
Index is assumed to be sorted. sort can be used to normalise a series.