Question

The DevExpress Grid (XtraGrid) allows grids and their groups to have summary calculations. The available options are Count, Max, Min, Avg, Sum, None and Custom.

Has anyone got some sample code that shows how to calculate a weighted average column, based upon the weightings provided as values in another column?

Was it helpful?

Solution

I ended up working this out, and will post my solution here in case others find it useful.

If a weighted average consists of both a value and a weight per row, then column that contains the value should have the weight GridColumn object assigned to its Tag property. Then, this event handler will do the rest:

private static void gridView_CustomSummaryCalculate(object sender, CustomSummaryEventArgs e)
{
    GridColumn weightColumn = ((GridSummaryItem)e.Item).Tag as GridColumn;

    if (weightColumn == null)
        return;

    switch (e.SummaryProcess)
    {
        case CustomSummaryProcess.Start:
        {
            e.TotalValue = new WeightedAverageCalculator();
            break;
        }
        case CustomSummaryProcess.Calculate:
        {
            double size = Convert.ToDouble(e.FieldValue);
            double weight = Convert.ToDouble(((GridView)sender).GetRowCellValue(e.RowHandle, weightColumn));

            ((WeightedAverageCalculator)e.TotalValue).Add(weight, size);
            break;
        }
        case CustomSummaryProcess.Finalize:
        {
            e.TotalValue = ((WeightedAverageCalculator)e.TotalValue).Value;
            break;
        }
    }
}

private sealed class WeightedAverageCalculator
{
    private double _sumOfProducts;
    private double _totalWeight;

    public void Add(double weight, double size)
    {
        _sumOfProducts += weight * size;
        _totalWeight += weight;
    }

    public double Value
    {
        get { return _totalWeight==0 ? 0 : _sumOfProducts / _totalWeight; }
    }
}

The code assumes that the underlying column values can be converted to doubles via Convert.ToDouble(object).

OTHER TIPS

If you provide your own lambda expression inside the sum you should be able to group them by a standard sum. I think this should work:

var grouped = from item in items
orderby item.Group
group item by item.Group into grp
select new
{
Average= grp.Sum(row => row.Value * row.Weight)
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top