Example #1
0
        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);
        }
Example #2
0
        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);
        }