C
C#2y ago
Whit

How to perform LINQ Average against collection of TValue constrained as INumber<TValue>

I would like to perform an average against a collection of TValue wherein I know TValue is a number because I've constrained it to INumber<TValue>. However, when trying to use it in the LINQ expression, it doesn't appear to know how to handle the arbitrary number type:
var avg = group.Average(v => v.Value);
var avg = group.Average(v => v.Value);
CS0029: Cannot implicitly convert type 'TValue' to 'long?'
Any guesses as to how I can handle this generically without writing a separate overload for every numeric type? Thank you!
12 Replies
Whit
WhitOP2y ago
Oddly, if I simply cast v.Value as dynamic, VS seems to think I'm casting to an int and returns a double and that's not right - as it might be a decimal that was provided.
Denis
Denis2y ago
Avoid using dynamic
Whit
WhitOP2y ago
I'd like to, but I'm not seeing much in the way of alternatives It's the only way not giving me squigglies
Denis
Denis2y ago
And if you avoid linq altogether and write a classic loop? Average should give you an double anyway
Whit
WhitOP2y ago
That might be blasphemy.. but also might be what's called for
Denis
Denis2y ago
So if you want it to be the same type as the input, you have to cast Not at all, I'd say it is perfectly fine. There are different types of averages anyway, so this allows you to be more specific
Whit
WhitOP2y ago
I'll give that a whirl - thanks for the suggestion
Denis
Denis2y ago
If group is an Ienumerable, make sure to materialize it to an array or smth. Or change the input argument to an iReadonlycollection This is to avoid multiple enumerations
Moods
Moods2y ago
Just curious, did you implement the Average method yourself? If so may I see it?
Whit
WhitOP2y ago
Working on it You're right - makes sense to return the average as a double
public static double Average<TValue>(this IEnumerable<TValue> values)
where TValue : INumber<TValue>
{
double sum = 0;
var count = 0;

foreach (var value in values.ToList())
{
sum += Convert.ToDouble(value);
count++;
}

return sum / count;
}
public static double Average<TValue>(this IEnumerable<TValue> values)
where TValue : INumber<TValue>
{
double sum = 0;
var count = 0;

foreach (var value in values.ToList())
{
sum += Convert.ToDouble(value);
count++;
}

return sum / count;
}
@moooodie
Moods
Moods2y ago
Oh you removed the function parameter
Denis
Denis2y ago
No need to do ToList since you are accessing the list only once Sorry, I didn't think of counting the number of entries in the loop

Did you find this page helpful?