C
C#16mo 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
WhitOP16mo 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
Denis16mo ago
Avoid using dynamic
Whit
WhitOP16mo 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
Denis16mo ago
And if you avoid linq altogether and write a classic loop? Average should give you an double anyway
Whit
WhitOP16mo ago
That might be blasphemy.. but also might be what's called for
Denis
Denis16mo 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
WhitOP16mo ago
I'll give that a whirl - thanks for the suggestion
Denis
Denis16mo 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
Moods16mo ago
Just curious, did you implement the Average method yourself? If so may I see it?
Whit
WhitOP16mo 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
Moods16mo ago
Oh you removed the function parameter
Denis
Denis16mo 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
Want results from more Discord servers?
Add your server