Home > Back-end >  Average of List<objects> in c#
Average of List<objects> in c#

Time:04-19

I have a list of object.

class Student
{
 int age;
 int height;
 int weight;
 int marksInMath;
 int marksInScience;
.
.
.
.
.
.
 int marksIn...;
}
List<Student> lst = new List<Student>();

I want to calculate median and average of this List. I am aware of

lst.Average(x=>x.Age);
lst.Average(x=>x.height);
.
.

Similarly for Median I can sort and then get median

lst.OrderBy(x=>x.Age);
//median logic on lst

But I don't want to repeat this code for every property(age, height, weight, marks, etc) in the object. Is there a way to do this in a loop or any other way so I don't have to get average for each property individually?

CodePudding user response:

Here's the one pass way to compute averages:

var averages =
    lst
        .Aggregate(
            new
            {
                N = 0,
                Age = 0,
                Height = 0,
                Weight = 0,
                MarksInMath = 0,
                MarksInScience = 0
            },
            (a, x) =>
                new
                {
                    N = a.N   1,
                    Age = a.Age   x.Age,
                    Height = a.Height   x.Height,
                    Weight = a.Weight   x.Weight,
                    MarksInMath = a.MarksInMath   x.MarksInMath,
                    MarksInScience = a.MarksInScience   x.MarksInScience,
                },
            a =>
                new
                {
                    Age = (double)a.Age / a.N,
                    Height = (double)a.Height / a.N,
                    Weight = (double)a.Weight / a.N,
                    MarksInMath = (double)a.MarksInMath / a.N,
                    MarksInScience = (double)a.MarksInScience / a.N,
                });

If you're after sums, stddev, etc, it's done the same way.

However, you're not going to be able compute the median without doing so on each property, one at a time.

CodePudding user response:

You can always have your own extension methods. for median and average you can use something like this:

public static class LinqExtentions
{
    public static double MedianOrDefault(this IEnumerable<int> src)
    {
        if (src == null)
            throw new ArgumentNullException(nameof(src));
        var data = src.OrderBy(n => n).ToArray();
        if (data.Length == 0)
            throw new InvalidOperationException();
        if (data.Length % 2 == 0)
            return (data[data.Length / 2 - 1]   data[data.Length / 2]) / 2.0;
        return data[data.Length / 2];
    }
    public static double AverageOrDefault(this IEnumerable<int> src)
    {
        if (src.Any())
            return src.Average();
        else
            return default(int);
    }
}

Now let's say that you have Student class with some simple fields:

public class Student
{
    public int age;
    public int height;
    public int weight;
    public int marksInMath;
    public int marksInScience;
}

And you can use your extensions as per the below sample:

var students = new List<Student>
{
    new Student{age = 15, height = 150},
    new Student{age = 19, height = 120},
    new Student{age = 13, height = 140},
    new Student{age = 20, height = 160},
    new Student{age = 11, height = 155},
};

Console.WriteLine(students.Select(x => x.age).MedianOrDefault());
Console.WriteLine(students.Select(x => x.height).AverageOrDefault());

Output:

Output Console

  •  Tags:  
  • c#
  • Related