Clearing a simple foreach with linq
The next method is quite simple, I am trying to determine the position rate by matching another property of the string to find the parent. I dislike this somewhat and am looking for elegant solutions to make the method smaller, more efficient, or both. He works in this current state and he doesn't like it noticeably inefficient or whatever. This is not a critical mission or anything more curiosity.
private decimal CalculateLaborTotal()
{
decimal result = 0;
foreach (ExtraWorkOrderLaborItem laborItem in Labor)
{
var rates = (from x in Project.ContractRates where x.ProjectRole.Name == laborItem.ProjectRole.Name select x).ToList();
if (rates != null && rates.Count() > 0)
{
result += laborItem.Hours * rates[0].Rate;
}
}
return result;
}
I love the idea of using it List<T>.ForEach()
, but I'm having trouble compressing it so it is still easy to read / maintain. Any thoughts?
a source to share
Something like this should do it (untested!):
var result =
(from laborItem in Labor
let rate = (from x in Project.ContractRates
where x.ProjectRole.Name == laborItem.ProjectRole.Name
select x).FirstOrDefault()
where rate != null
select laborItem.Hours * rate.Rate).Sum();
Or (assuming only one speed can match), the connection will be even neater:
var result =
(from laborItem in Labor
join rate in Project.ContractRates
on laborItem.ProjectRole.Name equals rate.ProjectRole.Name
select laborItem.Hours * rate.Rate).Sum();
a source to share
Okay, well how about this:
// Lookup from name to IEnumerable<decimal>, assuming Rate is a decimal
var ratesLookup = Project.ContractRates.ToLookup(x => x.ProjectRole.Name,
x => x.Rate);
var query = (from laborItem in Labor
let rate = ratesGroup[laborItem].FirstOrDefault()
select laborItem.Hours * rate).Sum();
The advantage is that you don't have to go through a potentially large list of contract rates every time - you create a search once. Of course, this is not a problem.
a source to share