Reputation: 53
ExtraTime in here represents extra time in Basketball. Since most matches don't have extra time, ExtraTime will be null many times.
I've searched other questions and wrote this and it worked. The code checks if is there any extra time, if not make it 0. And do not include 0's when calculating average.
OverTime = Math.Round(dtos.Select(p => (decimal)(p.ExtraTimeHomeTeamScore ?? 0)).Where(p => p != 0).Average(), 2),
Then i tried to do something more complex. This one to check two different data types and calculate average of them. Also don't include 0's. For some reason it returns Sequence Error.
OverTime = Math.Round((decimal)(dtos.Where(p => p.DataType == 0).Select(p => p.ExtraTimeHomeTeamScore ?? 0).Where( p => p != 0).Average()
+ dtos.Where(p => p.DataType == 1).Select(p => p.ExtraTimeAwayTeamScore ?? 0).Where(p => p != 0).Average()) / 2, 2)
I tried to write just like first code. Whatever i do, i couldn't get rid of Sequence Contains No Element Error. What part of my code is wrong, and can be improved?
Upvotes: 1
Views: 305
Reputation: 81493
Obviously you can't Average
nothing
However you can use Enumerable.DefaultIfEmpty
Returns the elements of an
IEnumerable<T>
, or a default valued singleton collection if the sequence is empty.
var result = dtos.Where(p => p.DataType == 0)
.Select(p => p.ExtraTimeHomeTeamScore ?? 0)
.Where( p => p != 0)
.DefaultIfEmpty(0)
.Average();
Upvotes: 2
Reputation: 26362
Check the IEnumerable.Average documentation:
Exceptions
ArgumentNullException
source is null.
InvalidOperationException
source contains no elements.
Your problem is when your filters (where clauses) return nothing. So when the resulting enumerables contain not elements, what would be the average value of them?
I would do something like this:
var filteredDtos1 = dtos.Where(p => p.DataType == 0).Select(p => p.ExtraTimeHomeTeamScore ?? 0).Where( p => p != 0);
var filteredDtos2 = dtos.Where(p => p.DataType == 1).Select(p => p.ExtraTimeAwayTeamScore ?? 0).Where(p => p != 0).Average();
var avg1 = filteredDtos1.Count > 0 : filteredDtos1.Average ? //some default value probably 0;
var avg2 = filteredDtos2.Count > 0 : filteredDtos2.Average ? //some default value probably 0;
OverTime = Math.Round((decimal)(avg1 + avg2) / 2, 2);
Upvotes: 1