// Create from expressions and heading public static OrderedIndex Create(ExpressionBlock[] exprs, DataHeading heading) { var seginfo = exprs.Select(e => new SegmentInfo { datatype = e.ReturnType, descending = e.IsDesc, grouped = e.IsGrouped, columnno = heading.FindIndex(e.ToDataColumn()), }).ToArray(); return(Create(seginfo)); }
// Transform with ordered calculations - different algorithm // 1. Build index // 2. Read input file using index // 3. Transform and write output file public override DataTable TransformOrdered(DataHeading newheading, ExpressionEval[] exprs, ExpressionEval[] orderexps) { Logger.WriteLine(4, "TransformOrdered {0} exprs={1},{2}", newheading, exprs.Count(), orderexps.Count()); var numacc = exprs.Where(e => e.HasFold).Sum(e => e.AccumCount); var newtable = DataTableLocal.Create(newheading); var newexprs = newtable.Heading.Reorder(exprs); var ordidx = OrderedIndex.Create(orderexps, Heading); // list of indexes of not-folded columns var notfold = exprs.Where(e => !e.HasFold) .Select(e => newheading.FindIndex(e.Name)).ToArray(); // Build index for (var ord = 0; ord < Cardinality; ++ord) //TODO:Enumerable { ordidx.Add(GetRow(ord), ord); } AccumulatorBlock accblk = null; // Read in index order, with access to ordering info DataRow lastrow = null; foreach (var ord in ordidx.RowOrdinals) { var oldrow = _rows[ord]; oldrow.OrderedIndex = ordidx; // so row functions can access it // if there is a group break, reset the accumulators if (ordidx.IsBreak) { accblk = AccumulatorBlock.Create(numacc); } DataRow newrow = oldrow.TransformAggregate(newheading, accblk, newexprs); // save the current row, output it on group break or when any non-fold column has changed // any rows not output will have identical non-fold cols so only running sums are lost var nfchg = (lastrow != null && !notfold.All(x => newrow.Values[x].Equals(lastrow.Values[x]))); if (nfchg || (lastrow != null && ordidx.IsBreak)) { newtable.AddRaw(lastrow); } lastrow = newrow; // guaranteed to be different! } if (lastrow != null) { newtable.AddRaw(lastrow); } Logger.WriteLine(4, "[{0}]", newtable); return(newtable); }
// Make an index (on this) where to find our fields in another heading // missing fields are -1 public int[] MakeIndex(DataHeading other) { return(Enumerable.Range(0, this.Degree) .Select(x => other.FindIndex(Columns[x])) .ToArray()); }
// Create a row that belongs to a table. // Can be called with a tuple or non-tuple heading. If the latter, reorder values to match tuple heading. public static DataRow Create(DataHeading heading, TypedValue[] values) { if (values.Length != heading.Degree) { throw new ArgumentOutOfRangeException("values", "wrong degree"); } Logger.Assert(values.All(v => v != null), "null value"); var newheading = (heading.IsTuple) ? heading : DataTypeTuple.Get(heading).Heading; var dr = new DataRow() { DataType = DataTypeTuple.Get(heading), Heading = newheading, _values = (heading.IsTuple) ? values : newheading.Columns.Select(c => values[heading.FindIndex(c)]).ToArray(), }; dr._hashcode = dr.CalcHashCode(); dr.Heading.CheckValues(dr.Values); return(dr); }