RamNow
RamNow

Reputation: 486

Pass aggregate function as parameter

I have a simple object:

public class Machine
{
    public string Name { get; set; }

    public int Power { get; set; }

    public int Type { get; set; }
}

Then there's a class which holds a List of these objects:

public class Aggregations
{
    private List<Machine> _machines;

    public Aggregations()
    {
        _machines = new List<Machine>
            {
                new Machine { Name = "XLR1", Power = 111, Type = 1 },
                new Machine { Name = "XLR2", Power = 222, Type = 1 },
                new Machine { Name = "XLR3", Power = 333, Type = 1 },
                new Machine { Name = "XLR4", Power = 444, Type = 1 },
                new Machine { Name = "XLR5", Power = 555, Type = 2 },
                new Machine { Name = "XLR6", Power = 666, Type = 2 }
            };           
    }
// ...
}

There're two functions which return lists of machines with specific criteria:

    public IEnumerable<Machine> MaxPower(IEnumerable<Machine> machines)
    {
        var maxPowerMachinesPerType = new List<Machine>();

        var groups = machines.GroupBy(m => m.Type);
        foreach (var g in groups)
        {
            var max = g.Max(m => m.Power);
            var machine = g.First(m => m.Power == max);
            maxPowerMachinesPerType.Add(machine);
        }

        return maxPowerMachinesPerType;
    }


    public IEnumerable<Machine> MinPower(IEnumerable<Machine> machines)
    {
        var minPowerMachinesPerType = new List<Machine>();

        var groups = machines.GroupBy(m => m.Type);
        foreach (var g in groups)
        {
            var min = g.Min(m => m.Power);
            var machine = g.First(m => m.Power == min);
            minPowerMachinesPerType.Add(machine);
        }

        return minPowerMachinesPerType;
    }
}

As you can see, the two functions are almost equal. Only "max" and "min" differ.

These functions are called like this:

IEnumerable<Machine> maxPowerMachines = MaxPower(_machines);
IEnumerable<Machine> minPowerMachines = MinPower(_machines);

Because my actual program is slightly more complex and I although would like to call other aggregate functions, I would like to pass the aggregate-function to be used as a parameter: (Pseudo-code)

IEnumerable<Machine> maxPowerMachines = SuperFunction(_machines, m => m.Max);
IEnumerable<Machine> minPowerMachines = SuperFunction(_machines, m => m.Min);
IEnumerable<Machine> averagePowerMachines = SuperFunction(_machines, m => m.Average);

I hope you get the intent.

Upvotes: 3

Views: 1129

Answers (2)

Ranger
Ranger

Reputation: 1174

Func<T> sounds like what you're looking for. The leading types <T> show the input, and the last <T> shows the return value, so you'd be looking for something like this:

    Func<IEnumerable<Machine>, IEnumerable<Machine>> aggregateFunction = MaxPower;


    //Now you can pass aggregateFunction around as a variable. You can call it like so:

    var machines = Aggregations();

    aggregateFunction.Invoke(machines);

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726579

Since Min and Max have the same signature, i.e. they both take IEnumerable<T> and produce a T, you can do it like this:

public IEnumerable<Machine> SelectPower(
    IEnumerable<Machine> machines
,   Func<IEnumerable<int>,int> powerSelector
) {
    var res = new List<Machine>();
    var groups = machines.GroupBy(m => m.Type);
    foreach (var g in groups) {
        var targetPower =  powerSelector(g.Select(m => m.Power));
        var machine = g.First(m => m.Power == targetPower);
        res.Add(machine);
    }
    return res;
}

Now you can call your method like this:

IEnumerable<Machine> maxPowerMachines = SuperFunction(_machines, m => m.Max());
IEnumerable<Machine> minPowerMachines = SuperFunction(_machines, m => m.Min());

Upvotes: 3

Related Questions