Batuhan Aydın
Batuhan Aydın

Reputation: 53

Sequence contains No elements when getting Null

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

Answers (2)

TheGeneral
TheGeneral

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

Athanasios Kataras
Athanasios Kataras

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

Related Questions