views:

194

answers:

6

I have a double[] array holding many numbers.

I have an algorithm that selects sections from within this array that fall under certain conditions (value greater than x, at least y values, etc.)

Now I want to calculate the average value of all these values in my section.

So, say my section is from index 20 to 40. Now I have 20 values. Is there an easy way to do this in C# or do I have to loop over my array and calculate the average by hand?

+1  A: 

Use Linq:

var myList = new double[] {1,2,3}
var avg = myList.Where(i => i > 1 && i < 2).Avg();
Arthur
This will not compile.
Jason
Waleed Al-Balooshi
I understood that the knows the index because of a predicate - second sentence. So: why not include the predicate.
Arthur
A: 

Use Enumerable.Average:

double[] values = new[] { 1.0, 2.0, 3.14, 2.71, 9.1 };
double average = values.Where(x => x > 2.0 && x < 4.0).Average();

Therefore, to use this with your selection methods you should consider having those methods return IEnumerable<double>. So, as an example:

public IEnumerable<double> GreaterThan(double[] values, double value) {
    for(int i = 0; i < values.Length; i++) {
        if(values[i] > value) {
            yield return values[i];
    }
}

Then:

// values is double[]
double average = GreaterThan(values, 2.0).Average();

You can even make the above an extension method so that it reads nicely:

double average = values.GreaterThan(2.0).Average();

I would encourage you to write your filtering methods to return IEnumerable<double>.

Jason
You do not select by index but by value.
Oliver Hanappi
@Oliver Hanappi: "I have an algorithm that selects sections from within this array that fall under certain conditions (value greater than x, at least y values, etc.)." He wants to more than just select by index. The above is just an example. The point is to have his methods return an `IEnumerable<double>` and then just let LINQ do the rest.
Jason
This also looks pretty cool. So the function GreaterThan already returns a segment of my array, right?But what if there can be n segments in that array?Say from index 10 to 20, and then from index 50 to 80?
Sebastian Hoitz
+4  A: 
var values = new[] { 1, 2, 3, 4, 5, 6, 7, 8 };
var average = values.Skip(2).Take(5).Average();
Oliver Hanappi
Beat me to it... +1 for doing it by index as he asked instead of filtering by value!
Aaronaught
@Aaronaught: "I have an algorithm that selects sections from within this array that fall under certain conditions (value greater than x, at least y values, etc.)." That is, selecting by index is not the only problem that he is trying to solve.
Jason
+1, really cool.
Benny
Thanks. This is pretty cool :)For clarification: I pre-check the section if it follows the conditions and then, once I have the boundaries, calculate the average.So this solution is perfectly valid.
Sebastian Hoitz
A: 

You can use the skip and take methods of linq to choose particular indexes:

var myData = new double[] { ..... };
var average = myList.Skip(20).Take(21).Average();
Jake Pearson
By using Take(20) you only get the numbers with index from 20 to 39.
Guffa
Good point, thanks.
Jake Pearson
A: 
double avg = array
    .Skip(startIndex)
    .Take(endIndex - startIndex + 1)
    .Average();
Lee
+1  A: 

Note that if you have the numbers with index 20 to 40, you don't have 20 numbers, you have 21 numbers.

You can use the Range method to create an IEnumerable for the indexes, then you can use the Average method to get the average of the numbers:

double average = Enumerable.Range(20, 21).Select(i => numbers[i]).Average();
Guffa