Reputation: 33
So I have a kindda odd scenario that I cannot get my head arround:
I have a outerlist which contains multiple innerlists.
Each innerlist contains multiple DataPoint objects.
Every innerlist contains the same amount of DataPoint objects.
A datapoint has a field called Value which is a double - e.g.:
So what I wanna do is to "combine" the innerlists into one List where the value of each DataPoint should be the average of the old values, based on its index in the list - in this case:
Is there any neat linq expression that could perform this kind of stuff (Im betting there are :))?
I ended up using the following solution:
var averages = Enumerable.Range(0, outer.First().Count()).Select(i => new DataPoint(outer.Select(l => l[i]).Average(x=>x.Value)));
which outputs IEnumerable, now with average valus - yay!
Upvotes: 3
Views: 686
Reputation: 6908
This is all you need:
var outer = new List<List<List<double>>>();
var l1 = outer.Select(
x => new List<double> {
x.Average(y => y[0]),
x.Average(y => y[1]),
x.Average(y => y[2])
});
With a data structure like yours, it would be:
var list = items.Select(x => new List<DataPoint> (
Enumerable.Range(0,3).Select(z =>
new DataPoint {
Value = x.InnerLists.Average(y => y.DataPoints[z].Value)})
));
(Thank you to whomever suggested the Enumerable.Range
)
Upvotes: 0
Reputation:
I'm on my iPad, so I havent compiled, but the following should work:
Enumerable.Range(0,outer.First().Length).
Select(i => outer.Select(l => l[i]).Average());
Upvotes: 1
Reputation: 241641
Start with an extension method to take a slice of the inner lists:
public static IEnumerable<double> Slice(
this IEnumerable<List<DataPoint>> innerLists,
int index) {
foreach(var innerList in innerLists) {
yield return innerList.DataPoints[index].Value;
}
}
}
Then:
var averages = Enumerable.Range(0, count)
.Select(index => outerList.InnerLists.Slice(index))
.Select(slice => slice.Average());
I am assuming a hierarchy like this:
class DataPoint { public double Value { get; set; } }
class InnerList { public List<DataPoint> DataPoints { get; set; } }
class OuterList { public IEnumerable<InnerList> InnerLists { get; set; } }
but the above idea is obviously adaptable to however exactly you have structured your data.
Upvotes: 3
Reputation: 164291
The key here would be to group the inner list values by their index. Something like this would work:
// Test data
var list = new List<List<double>>() {
new List<double> { 2, 2 },
new List<double> { 4, 5 },
new List<double> { 3, 5 }
};
// Created groups based on index
var lookup = from inner in list
from value in inner.Select((n,idx) => new { n,idx })
group value by value.idx;
// Calculate averages
var averagesBasedOnIndex = lookup.Select(g => g.Average(x => x.n)).ToList();
Upvotes: 2