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: