public static ICube MergeQuick(this ICube baseCube, ICube otherCube) { if (!Enumerable.SequenceEqual(baseCube.DataTypes.Keys, otherCube.DataTypes.Keys) || !Enumerable.SequenceEqual(baseCube.DataTypes.Values, otherCube.DataTypes.Values)) { throw new Exception("Cubes must be of same type to be merged"); } var o = new ResultCube(); o.Initialize(baseCube.DataTypes); var baseRows = baseCube.GetAllRows().ToArray(); var otherRows = otherCube.GetAllRows().ToArray(); for (var i = 0; i < baseRows.Length; i++) { var br = baseRows[i]; o.AddRow(br.MetaData, br.Value); } for (var i = 0; i < otherRows.Length; i++) { var br = otherRows[i]; o.AddRow(br.MetaData, br.Value); } return(o); }
/// <summary> /// Differences two cubes, assuming same number and same order of rows in both /// </summary> /// <param name="baseCube"></param> /// <param name="cubeToSubtract"></param> /// <returns></returns> public static ICube QuickDifference(this ICube baseCube, ICube cubeToSubtract) { if (!Enumerable.SequenceEqual(baseCube.DataTypes.Keys, cubeToSubtract.DataTypes.Keys) || !Enumerable.SequenceEqual(baseCube.DataTypes.Values, cubeToSubtract.DataTypes.Values)) { throw new Exception("Cubes must be of same type to be differenced"); } var o = new ResultCube(); o.Initialize(baseCube.DataTypes); var baseRows = baseCube.GetAllRows().ToArray(); var subRows = cubeToSubtract.GetAllRows().ToArray(); if (baseRows.Length != subRows.Length) { throw new Exception("Cubes must have same number of rows to quick-diff them"); } for (var i = 0; i < baseRows.Length; i++) { var br = baseRows[i]; var sr = subRows[i]; o.AddRow(br.MetaData, br.Value - sr.Value); } return(o); }
public static ICube Sort(this ICube cube, List <string> fieldsToSortOn) { foreach (var fieldToSortOn in fieldsToSortOn) { if (!cube.DataTypes.ContainsKey(fieldToSortOn)) { throw new Exception($"Cannot sort on field {fieldToSortOn} as it is not present"); } } var outCube = new ResultCube(); outCube.Initialize(cube.DataTypes); var fieldNames = cube.DataTypes.Keys.ToList(); var indexes = fieldsToSortOn.Select(x => fieldNames.IndexOf(x)).Reverse(); var rows = new List <ResultCubeRow>(cube.GetAllRows()); foreach (var ix in indexes) { rows = rows.OrderBy(x => x.MetaData[ix]).ToList(); } foreach (var row in rows) { outCube.AddRow(row.MetaData, row.Value); } return(outCube); }
public static ICube Filter(this ICube cube, List <KeyValuePair <string, object> > fieldsToFilterOn, bool filterOut = false) { foreach (var fieldToFilterOn in fieldsToFilterOn.Select(x => x.Key)) { if (!cube.DataTypes.ContainsKey(fieldToFilterOn)) { throw new Exception($"Cannot filter on field {fieldToFilterOn} as it is not present"); } } var outCube = new ResultCube(); outCube.Initialize(cube.DataTypes); var fieldNames = cube.DataTypes.Keys.ToList(); var indexes = fieldsToFilterOn .Select(x => x.Key) .Distinct() .ToDictionary(x => x, x => fieldNames.IndexOf(x)); var values = new Dictionary <string, List <object> >(); foreach (var kv in fieldsToFilterOn) { if (!values.ContainsKey(kv.Key)) { values[kv.Key] = new List <object> { kv.Value } } ; else { values[kv.Key].Add(kv.Value); } } foreach (var row in cube.GetAllRows()) { var rowIsRelevant = true; foreach (var kv in values) { if (!kv.Value.Any(v => IsEqual(row.MetaData[indexes[kv.Key]], v))) { rowIsRelevant = false; break; } } if (filterOut) { rowIsRelevant = !rowIsRelevant; } if (rowIsRelevant) { outCube.AddRow(row.MetaData, row.Value); } } return(outCube); }
public static ICube BucketTimeAxis(this ICube cube, string timeFieldName, string bucketedFieldName, Dictionary <DateTime, string> bucketBoundaries) { if (!cube.DataTypes.ContainsKey(timeFieldName)) { throw new Exception($"Cannot filter on field {timeFieldName} as it is not present"); } var outCube = new ResultCube(); var newTypes = new Dictionary <string, Type>(cube.DataTypes); newTypes.Add(bucketedFieldName, typeof(string)); outCube.Initialize(newTypes); var buckets = bucketBoundaries.Keys.OrderBy(x => x).ToList(); var bucketFieldIx = cube.GetColumnIndex(timeFieldName); foreach (var row in cube.GetAllRows()) { var date = (DateTime)row.MetaData[bucketFieldIx]; var bucket = buckets.BinarySearch(date); if (bucket < 0) { bucket = ~bucket; } var bucketLabel = bucketBoundaries[buckets[bucket]]; var metaList = new List <object>(row.MetaData) { bucketLabel }; outCube.AddRow(metaList.ToArray(), row.Value); } return(outCube); }
public static ICube Difference(this ICube baseCube, ICube cubeToSubtract) { if (!Enumerable.SequenceEqual(baseCube.DataTypes.Keys, cubeToSubtract.DataTypes.Keys) || !Enumerable.SequenceEqual(baseCube.DataTypes.Values, cubeToSubtract.DataTypes.Values)) { throw new Exception("Cubes must be of same type to be differenced"); } var o = new ResultCube(); o.Initialize(baseCube.DataTypes); var baseRows = baseCube.GetAllRows().ToList(); var subRows = cubeToSubtract.GetAllRows().ToList(); foreach (var br in baseRows) { var rowFound = false; foreach (var sr in subRows) { if (Enumerable.SequenceEqual(br.MetaData, sr.MetaData)) { o.AddRow(br.MetaData, br.Value - sr.Value); subRows.Remove(sr); rowFound = true; break; } } if (!rowFound) //zero to subtract { o.AddRow(br.MetaData, br.Value); } } //look at what is left in subrows foreach (var sr in subRows) { o.AddRow(sr.MetaData, -sr.Value); } return(o); }
public static ICube ScalarMultiply(this ICube cube, double scalar) { var outCube = new ResultCube(); outCube.Initialize(cube.DataTypes); var rows = new List <ResultCubeRow>(cube.GetAllRows()); foreach (var row in rows) { outCube.AddRow(row.MetaData, row.Value * scalar); } return(outCube); }
public static ICube Filter(this ICube cube, Dictionary <string, object> fieldsToFilterOn, bool filterOut = false) { foreach (var fieldToFilterOn in fieldsToFilterOn.Keys) { if (!cube.DataTypes.ContainsKey(fieldToFilterOn)) { throw new Exception($"Cannot filter on field {fieldToFilterOn} as it is not present"); } } var outCube = new ResultCube(); outCube.Initialize(cube.DataTypes); var fieldNames = cube.DataTypes.Keys.ToList(); var indexes = fieldsToFilterOn.Keys.ToDictionary(x => x, x => fieldNames.IndexOf(x)); foreach (var row in cube.GetAllRows()) { var rowIsRelevant = true; foreach (var kv in fieldsToFilterOn) { if (!IsEqual(row.MetaData[indexes[kv.Key]], Convert.ChangeType(kv.Value, cube.DataTypes[kv.Key]))) { rowIsRelevant = false; break; } } if (filterOut) { rowIsRelevant = !rowIsRelevant; } if (rowIsRelevant) { outCube.AddRow(row.MetaData, row.Value); } } return(outCube); }
public static ICube Sort(this ICube cube) { var outCube = new ResultCube(); outCube.Initialize(cube.DataTypes); var fieldNames = cube.DataTypes.Keys.ToList(); var indexes = Enumerable.Range(0, fieldNames.Count).Reverse().ToArray(); var rows = new List <ResultCubeRow>(cube.GetAllRows()); foreach (var ix in indexes) { rows = rows.OrderBy(x => x.MetaData[ix]).ToList(); } foreach (var row in rows) { outCube.AddRow(row.MetaData, row.Value); } return(outCube); }
public static ICube Pivot(this ICube cube, string[] fieldsToAggregateBy, AggregationAction aggregationAction) { //for now, aggregate only works on numerical fields and performs a sum foreach (var fieldToAggregateBy in fieldsToAggregateBy) { if (!cube.DataTypes.ContainsKey(fieldToAggregateBy)) { throw new Exception($"Cannot aggregate on field {fieldToAggregateBy} as it is not present"); } } var types = cube.DataTypes.Keys.ToList(); var ixs = fieldsToAggregateBy.Select(f => types.IndexOf(f)).ToArray(); var rows = cube.GetAllRows(); var distinctValues = rows.Select(x => string.Join("~", ixs.Select(ix => x.MetaData[ix]?.ToString() ?? string.Empty))).Distinct(); var outCube = new ResultCube(); var oT = new Dictionary <string, Type>(); foreach (var fieldToAggregateBy in fieldsToAggregateBy) { oT.Add(fieldToAggregateBy, cube.DataTypes[fieldToAggregateBy]); } outCube.Initialize(oT); var aggData = new Dictionary <string, double>(); var aggDataCount = new Dictionary <string, int>(); var metaDict = new Dictionary <string, object[]>(); foreach (var row in rows) { var rowKey = string.Join("~", ixs.Select(i => row.MetaData[i]?.ToString() ?? string.Empty)); if (!aggData.ContainsKey(rowKey)) { if (aggregationAction == AggregationAction.Min) { aggData[rowKey] = double.MaxValue; } else if (aggregationAction == AggregationAction.Max) { aggData[rowKey] = double.MinValue; } else { aggData[rowKey] = 0; } aggDataCount[rowKey] = 0; var filetedMetaData = new object[ixs.Length]; for (var i = 0; i < ixs.Length; i++) { filetedMetaData[i] = row.MetaData[ixs[i]]; } metaDict[rowKey] = filetedMetaData; } switch (aggregationAction) { case AggregationAction.Sum: aggData[rowKey] += row.Value; break; case AggregationAction.Average: aggData[rowKey] += row.Value; aggDataCount[rowKey]++; break; case AggregationAction.Min: aggData[rowKey] = System.Math.Min(aggData[rowKey], row.Value); break; case AggregationAction.Max: aggData[rowKey] = System.Math.Max(aggData[rowKey], row.Value); break; } } //final post-processing for average foreach (var rowKey in aggData.Keys.ToList()) { var rowDict = new Dictionary <string, object>(); if (aggregationAction == AggregationAction.Average) { aggData[rowKey] /= aggDataCount[rowKey]; } outCube.AddRow(metaDict[rowKey], aggData[rowKey]); } return(outCube); }
public static ICube Merge(this ICube baseCube, ICube otherCube) { //add check that common fields are of them same type... foreach (var kv in baseCube.DataTypes.Where(x => otherCube.DataTypes.Keys.Contains(x.Key))) { if (kv.Value != otherCube.DataTypes[kv.Key]) { throw new Exception($"Data types dont match for field {kv.Key}"); } } var newDataTypes = new Dictionary <string, Type>(); foreach (var kv in baseCube.DataTypes) { newDataTypes[kv.Key] = kv.Value; } foreach (var kv in otherCube.DataTypes) { newDataTypes[kv.Key] = kv.Value; } var o = new ResultCube(); o.Initialize(newDataTypes); var baseRows = baseCube.GetAllRows().ToArray(); var otherRows = otherCube.GetAllRows().ToArray(); var baseIx = baseCube.DataTypes.Keys.Select(k => o.GetColumnIndex(k)).ToArray(); var otherIx = otherCube.DataTypes.Keys.Select(k => o.GetColumnIndex(k)).ToArray(); var cleanRow = o.DataTypes.Select(kv => GetDefaultValue(kv.Value)).ToArray(); for (var i = 0; i < baseRows.Length; i++) { var row = new object[cleanRow.Length]; Array.Copy(cleanRow, row, row.Length); var br = baseRows[i]; for (var j = 0; j < baseIx.Length; j++) { row[baseIx[j]] = br.MetaData[j]; } o.AddRow(row, br.Value); } for (var i = 0; i < otherRows.Length; i++) { var br = otherRows[i]; var row = new object[cleanRow.Length]; Array.Copy(cleanRow, row, row.Length); for (var j = 0; j < baseIx.Length; j++) { row[baseIx[j]] = br.MetaData[j]; } o.AddRow(row, br.Value); } return(o); }