public DynamicFormulaMeasure(string formula, IPivotData pvtData) { Parser = new LambdaParser(); Formula = formula; var formulaExpr = Parser.Parse(formula); var formulaParams = LambdaParser.GetExpressionParameters(formulaExpr); var paramMeasureIndexes = new List <int>(); var paramMeasureNames = new List <string>(); foreach (var fParam in formulaParams) { if (paramMeasureNames.Contains(fParam.Name)) { continue; // avoid duplicates } var paramMsrIdx = ResolveAggregatorIndex(fParam.Name, pvtData); if (paramMsrIdx >= 0) { paramMeasureIndexes.Add(paramMsrIdx); paramMeasureNames.Add(fParam.Name); } } ArgMeasureIndexes = paramMeasureIndexes.ToArray(); ParamNameToArgIdx = new Dictionary <string, int>(); for (int i = 0; i < paramMeasureNames.Count; i++) { ParamNameToArgIdx[paramMeasureNames[i]] = i; } }
/// <summary> /// Initializes new slicing query to specified <see cref="PivotData"/> instance. /// </summary> /// <param name="pvtData">multidimensional dataset to query</param> public SliceQuery(IPivotData pvtData) { PvtData = pvtData; DimSelectors = new List <DimensionSelector>(); AggrSelectors = new List <AggregatorSelector>(); FilterHandlers = new List <Func <KeyValuePair <object[], IAggregator>, bool> >(); }
public FilterPivotData(string[] dims, IAggregatorFactory aggr, IPivotData origPvtData, Func <KeyValuePair <object[], IAggregator>, bool> filterHandler, Func <KeyValuePair <object[], IAggregator>, object[]> keyHandler, Func <KeyValuePair <object[], IAggregator>, IAggregator> aggrHandler) { Dims = dims; Aggr = aggr; PvtData = origPvtData; FilterHandler = filterHandler; KeyHandler = keyHandler; AggrHandler = aggrHandler; }
PivotData GetGrandTotalPvtData(IPivotData basePvtData) { // this is grand-total var grandTotalPvtData = new PivotData(emptyStringArray, PvtData.AggregatorFactory); var grandTotalAggr = grandTotalPvtData[emptyObjectArray]; foreach (var entry in basePvtData) { grandTotalAggr.Merge(entry.Value); } return(grandTotalPvtData); }
/// <summary> /// Initializes new instance of <see cref="PivotTable"/> instance by specified <see cref="PivotData"/> /// </summary> /// <param name="axes">list of axes determined by dimensions</param> /// <param name="dataCube">multidimensional dataset used for calculating pivot table</param> /// <param name="axesComparers">list of custom comparers for sorting axes keys</param> public PivotTableMD(string[][] axes, IPivotData pvtData, IComparer <ValueKey>[] axesComparers) { Axes = axes; PvtData = pvtData; AxesIndexes = axes.Select(axis => GetDimIdx(axis)).ToArray(); AxesKeys = new ValueKey[Axes.Length][]; for (int i = 0; i < Axes.Length; i++) { AxesKeys[i] = GetAxisKeys(i, axesComparers != null && i < axesComparers.Length && axesComparers[i] != null ? axesComparers[i] : NaturalSortKeyComparer.Instance); } }
internal TotalsCachePivotData(IPivotData pvtData) { PvtData = pvtData; if (pvtData.Dimensions.Length <= 64) { GetValueHandler = new UlongMaskCache(this).Get; } else { GetValueHandler = new BitArrayMaskCache(this).Get; } }
internal PivotDataMember(IPivotData pvtData, string[] aggrNames) { PvtData = pvtData; DimToIdx = new Dictionary <string, int>(pvtData.Dimensions.Length); for (int i = 0; i < pvtData.Dimensions.Length; i++) { DimToIdx[pvtData.Dimensions[i]] = i; } AggrToIdx = new Dictionary <string, int>(aggrNames.Length); for (int i = 0; i < aggrNames.Length; i++) { AggrToIdx[aggrNames[i]] = i; } }
/// <summary> /// Processes data from the specified <see cref="IPivotData"/> instance and calculates <see cref="PivotData"/> values /// </summary> /// <param name="data">input data represented by <see cref="IPivotData"/> instance</param> /// <param name="aggregatorNames">field names for accessing aggregator values</param> /// <remarks> /// This overload allows to use values of another data cube as input. /// <example> /// Lets assume that we need to calculate average over values that are calculated in another cube: /// <code> /// IPivotData sourcePvtData; // dimensions: "month", "store" and one sum measure /// var pvtData = new PivotData(new[] {"store"}, new AverageAggregatorFactory("value") ); /// pvtData.ProcessData(sourcePvtData, "value"); /// </code> /// </example> /// </remarks> public void ProcessData(IPivotData data, params string[] aggregatorNames) { var aggrCount = 1; if (data.AggregatorFactory is CompositeAggregatorFactory) { aggrCount = ((CompositeAggregatorFactory)data.AggregatorFactory).Factories.Length; } if (aggregatorNames.Length > aggrCount) { throw new ArgumentOutOfRangeException("Number of aggregators is less than number of provided names."); } var pvtDataMember = new PivotDataMember(data, aggregatorNames); ProcessData(data, pvtDataMember.GetValue); }
/// <summary> /// Initializes a new instance of <see cref="PivotTable"/> instance by specified <see cref="PivotData"/> /// </summary> /// <param name="rows">list of dimensions for determining table rows</param> /// <param name="columns">list of dimensions for determining table columns</param> /// <param name="pvtData">multidimensional dataset used for pivot table calculation</param> /// <param name="rowKeysComparer">custom table row keys comparer (if null <see cref="NaturalSortKeyComparer"/> is used)</param> /// <param name="colKeysComparer">custom table row keys comparer (if null <see cref="NaturalSortKeyComparer"/> is used)</param> public PivotTable(string[] rows, string[] columns, IPivotData pvtData, IComparer <ValueKey> rowKeysComparer, IComparer <ValueKey> colKeysComparer) { PreserveGroupOrder = false; TotalsCache = true; Columns = columns ?? new string[0]; Rows = rows ?? new string[0]; PvtData = pvtData; TotalsCachePvtData = new TotalsCachePivotData(pvtData); ColumnIndexes = GetDimIdx(Columns); RowIndexes = GetDimIdx(Rows); AlwaysHasEmpty = ColumnIndexes.Union(RowIndexes).Count() < PvtData.Dimensions.Length; IsMultiValue = pvtData.AggregatorFactory is CompositeAggregatorFactory; GenerateAxesKeys(); SortKeys(ColumnKeys, Columns, colKeysComparer ?? NaturalSortKeyComparer.Instance); SortKeys(RowKeys, Rows, rowKeysComparer ?? NaturalSortKeyComparer.Instance); }
/// <summary> /// Returns unique keys of specified dimensions for the <see cref="IPivotData"/> instance. /// </summary> /// <param name="pvtData"><see cref="IPivotData"/> instance</param> /// <param name="dims">list of dimensions</param> /// <param name="dimSortComparers">list of comparers that should be used for sorting dimension keys</param> /// <returns>array of keys for specified dimensions</returns> public static object[][] GetDimensionKeys(IPivotData pvtData, string[] dims, IComparer <object>[] dimSortComparers) { if (dims == null) { dims = pvtData.Dimensions; } var dimLen = dims.Length; var dimKeysArr = new object[dimLen][]; var dimKeys = new HashSet <object> [dimLen]; var dimIndexes = new int[dimLen]; int d; for (d = 0; d < dimLen; d++) { var dimIdx = Array.IndexOf(pvtData.Dimensions, dims[d]); if (dimIdx < 0) { throw new ArgumentOutOfRangeException("dims", String.Format("Unknown dimension: {0}", dims[d])); } dimIndexes[d] = dimIdx; dimKeys[d] = new HashSet <object>(); } foreach (var entry in pvtData) { for (d = 0; d < dimLen; d++) { dimKeys[d].Add(entry.Key[dimIndexes[d]]); } } for (d = 0; d < dims.Length; d++) { dimKeysArr[d] = new object[dimKeys[d].Count]; dimKeys[d].CopyTo(dimKeysArr[d]); if (dimSortComparers != null) { // apply sort Array.Sort(dimKeysArr[d], d < dimSortComparers.Length && dimSortComparers[d] != null ? dimSortComparers[d] : NaturalSortKeyComparer.Instance); } } return(dimKeysArr); }
int ResolveAggregatorIndex(string name, IPivotData pvtData) { var aggrFactories = pvtData.AggregatorFactory is CompositeAggregatorFactory ? ((CompositeAggregatorFactory)pvtData.AggregatorFactory).Factories : new [] { pvtData.AggregatorFactory }; for (int i = 0; i < aggrFactories.Length; i++) { var indexBasedName = "value" + i.ToString(); if (name == indexBasedName) { return(i); } var aggrFactoryName = aggrFactories[i].ToString().ToLower().Replace(" ", ""); if (name == aggrFactoryName) { return(i); } } return(-1); }
PivotData GetReducedPivotData(IPivotData basePvtData, object[] key, int emptyDims) { if (emptyDims == key.Length) { // this is grand-total return(GetGrandTotalPvtData(basePvtData)); } var sliceQuery = new SliceQuery(basePvtData); for (int i = 0; i < key.Length; i++) { if (Key._Empty != key[i]) { sliceQuery.Dimension(PvtData.Dimensions[i]); } } var reducedPvtData = sliceQuery.Execute(); reducedPvtData.LazyAdd = false; return(reducedPvtData); }
DataTable getPivotDataAsTable(IPivotData pvtData) { var tbl = new DataTable(); // create columns by pivot data foreach (var dim in pvtData.Dimensions) { tbl.Columns.Add(dim, typeof(object)); } if (pvtData.AggregatorFactory is CompositeAggregatorFactory) { var aggrFactories = ((CompositeAggregatorFactory)pvtData.AggregatorFactory).Factories; for (int i = 0; i < aggrFactories.Length; i++) { tbl.Columns.Add(String.Format("value_{0}", i), typeof(object)); } } else { tbl.Columns.Add("value", typeof(object)); } // add rows foreach (var entry in pvtData) { var vals = new object[tbl.Columns.Count]; for (int i = 0; i < entry.Key.Length; i++) { vals[i] = entry.Key[i]; } var aggr = entry.Value.AsComposite(); for (int i = 0; i < aggr.Aggregators.Length; i++) { vals[entry.Key.Length + i] = aggr.Aggregators[i].Value; } tbl.Rows.Add(vals); } tbl.AcceptChanges(); return(tbl); }
/// <summary> /// Modifies the current <see cref="PivotData"/> object to merge values from itself and specified <see cref="PivotData"/>. /// </summary> /// <remarks> /// Only compatible <see cref="PivotData"/> objects could be merged: they should have the same AggregatorFactory and Dimensions configuration. /// This method is also useful for organizing parallel data aggregation algorithm. /// </remarks> /// <param name="pvtData">multidimensional dataset to merge</param> public virtual void Merge(IPivotData pvtData) { if (!AggregatorFactory.Equals(pvtData.AggregatorFactory)) { throw new ArgumentException("AggregatorFactory mismatch"); } if (Dimensions.Length != pvtData.Dimensions.Length) { throw new ArgumentException("Dimensions mismatch"); } for (int i = 0; i < Dimensions.Length; i++) { if (!Dimensions[i].SequenceEqual(pvtData.Dimensions[i])) { throw new ArgumentException(String.Format("Dimension {0} elements mismatch", i)); } } // remove all totals totalValues.Clear(); valuesArr = null; IAggregator aggr; foreach (var dp in pvtData) { if (!values.TryGetValue(dp.Key, out aggr)) { aggr = aggregatorFactory.Create(); values[dp.Key] = aggr; } aggr.Merge(dp.Value); } if (!lazyTotals) { BatchCalcTotals(); } }
public PivotDataState(IPivotData pvtData) { var allRawKeys = new List <object>(); var keyIdx = new Dictionary <object, uint>(pvtData.Count); var allVkRefs = new uint[pvtData.Count][]; var allRawVals = new object[pvtData.Count]; uint i, idx; int dimCnt = pvtData.Dimensions.Length; object[] vk; int valIdx = 0; foreach (var entry in pvtData) { vk = entry.Key; var vkIdx = new uint[dimCnt]; for (i = 0; i < dimCnt; i++) { if (!keyIdx.TryGetValue(vk[i], out idx)) { idx = (uint)allRawKeys.Count; allRawKeys.Add(vk[i]); keyIdx[vk[i]] = idx; } vkIdx[i] = idx; } allVkRefs[valIdx] = vkIdx; allRawVals[valIdx] = entry.Value.GetState(); valIdx++; } DimCount = (uint)dimCnt; KeyValues = allRawKeys.ToArray(); ValueKeys = allVkRefs; Values = allRawVals; }
/// <summary> /// Initializes new instance of <see cref="PivotTable"/> instance by specified <see cref="PivotData"/> /// </summary> /// <param name="axes">list of axes determined by dimensions</param> /// <param name="pvtData">multidimensional dataset used for pivot table calculation</param> public PivotTableMD(string[][] axes, IPivotData pvtData) : this(axes, pvtData, null) { }
/// <summary> /// Initializes a new instance of <see cref="PivotTable"/> instance by specified <see cref="PivotData"/> /// </summary> /// <param name="rows">list of dimensions for determining table rows</param> /// <param name="columns">list of dimensions for determining table columns</param> /// <param name="pvtData">multidimensional dataset used for pivot table calculation</param> public PivotTable(string[] rows, string[] columns, IPivotData pvtData) : this(rows, columns, pvtData, null, null) { }