Sam Goldberg
Sam Goldberg

Reputation: 6801

What is correct Linq syntax to get multiple aggregate results from a list of integers in single iteration

I have a list of integers and I want to calculate: Count, Max, Min, Average using Linq syntax. I know that the following all work fine:

var avg = list.Average();
var max = list.Max(); 

and so on. But I can't figure out the correct Linq syntax to do this in a single iteration, i.e. the equivalent of SQL:

select Min(value), Max(value), Avg(value) from list

Upvotes: 2

Views: 381

Answers (2)

Berkay Yaylacı
Berkay Yaylacı

Reputation: 4513

What about this? Before select, order list ASC will be useful

List<double> list = new List<double>() { 15,116,17,21,333,44,55,11};

double max = 0;
double min = 0;
double avg = list.OrderBy(x => x).Select((x, index) => index == 0 ? min = x : max = x).Average();

Hope helps,

Upvotes: 1

NetMage
NetMage

Reputation: 26927

If your list is src, you can use a ValueTuple and Aggregate to make a hard to read loop:

var ans = src.Aggregate((Count: 0, Min: Int32.MaxValue, Max: Int32.MinValue, Sum: 0),
                        (g, v) => (g.Count+1, v < g.Min ? v : g.Min, v > g.Max ? v : g.Max, g.Sum+v));
var count = ans.Count;
var min = ans.Min;
var max = ans.Max;
var avg = ans.Sum / (double)(ans.Count == 0 ? 1 : ans.Count);

Of course, if it is something you might want to do often, you can create an extension method for it:

public static class IEnumerableExt {
    public static (int Count, int Min, int Max, double Average) Stats(this IEnumerable<int> src) {
        var a = src.Aggregate((Count: 0, Min: Int32.MaxValue, Max: Int32.MinValue, Sum: 0),
                              (g, v) => (g.Count + 1, v < g.Min ? v : g.Min, v > g.Max ? v : g.Max, g.Sum + v));
        return (a.Count, a.Min, a.Max, a.Sum / (double)(a.Count == 0 ? 1 : a.Count));
    }
}

The loop version is more verbose but arguably easier to understand:

public static (int Count, int Min, int Max, double Average) Stats2(this IEnumerable<int> src) {
    var count = 0;
    var min = Int32.MaxValue;
    var max = Int32.MinValue;
    var sum = 0;

    foreach (var i in src) {
        ++count;
        if (i < min)
            min = i;
        if (i > max)
            max = i;
        sum += i;
    }

    return (count, min, max, sum / (double)(count == 0 ? 1 : count));
}

Upvotes: 2

Related Questions