Reputation: 8147
Is it possible to have two projections, .Select(...)
, in one same query?
int total = ...;
var sendersInfo = db.Persons
.Select(p => new
{
sentSMS = p.SentSMS.Count(...large expression...),
})
// Calculate percentages
.Select(i => new
{
sentSMS = i.sentSMS,
percentage = i.sentSMS/total * 100
});
The above is not working because apparently "i.sentSMS" isn't calculated yet and so a 0 (zero) is being used instead of the result.
What I'm trying to avoid is this (below), which does work, but has repeated code "...large expression...":
int total = ...;
var sendersInfo = db.Persons
.Select(p => new
{
sentSMS = p.SentSMS.Count(...large expression...),
percentage = p.SentSMS.Count(...large expression...) / total * 100
});
Beside my question ("is it possible..."), is there a best way to achieve this? I don't like uggly code. Also I'm trying to achieve this in pure Linq-to-entities (no linq-to-objects)
Upvotes: 0
Views: 127
Reputation: 2026
Commenting on your comment:
You do not need to cast to float every time - as soon as one of the operands is a float, the other is promoted, so the result is of type which bears a higher precision (float > int).
There are two arithmetic operations in line:
i.sentSMS / total * 100
// (1) (2)
Division, then multiplying. Both operators /
and *
have the same priority (refer to e.g. this), so the expression is evaluated from the left side, first computing the quotient (because both dividend and divisor are int
, the result is also int
), then multiplying the result with 100
(also int
).
So, instead of doing
(float)i.sentSMS / (float)total * 100
It suffices to do:
// ┌─ (float) thanks to casting
// │ ┌─ (int) -> (float) promotion here, making the result of division a (float) too
// │ │ ┌─ then 100 gets promoted in the second step the same way
(float)i.sentSMS / total * 100
And even shorter so:
// ┌─ (float) literal, because 100 is an (int) literal and 100.0 (or 100d) is a (double) literal
// │ ┌─ (int) -> (float) promotion
// │ │ ┌─ and again
100f * i.sentSMS / total
100f
being a literal for float
(same as (float)100
, but neater) :)
In my opinion 100.0
looks even better, but it is a literal for double
, even greater precision, so all the float
s will get promoted to double
, making the result double
as well, and so you would get a compiler warning for losing precision while assigning double
result to float
variable.
Upvotes: 1