Trying to sum compute my select statement - linq

I want to rewrite this statement into a Linq statement with lambda.
var summe1 = (from l in db.Lg7s
&& new int[]{0,40}.Contains(l.REATE)
&& l.ANSWERING>0
select (l.TALKINGTIME + l.ONHOLDTIME + l.ACTIONTIME + l.UPTIME)).Sum(i => i);
I tried to do it like this:
T4Number = group
.Where(lg => new int[]{38,40}.Contains(lg.CAUSE) && lg.ANSWERING>0)
.Select(lg => new {DurationOfCallProcessing = lg.EN_ TALKINGTIME + lg.EN_ ONHOLDTIME + lg.EN_ ACTIONTIME + lg.UPTIME })
.Sum()
But the ide said, that Sum isnĀ“t valid.

You cannot "Sum" an anonymous type. I guess you want:
T4Number = group
.Where(lg => new int[]{38,40}.Contains(lg.CAUSE) && lg.ANSWERING>0)
.Select(lg => new {DurationOfCallProcessing = lg.EN_ TALKINGTIME + lg.EN_ ONHOLDTIME + lg.EN_ ACTIONTIME + lg.UPTIME })
.Sum(x => x.DurationOfCallProcessing);
But if you only want the sum there is no need to create the anonymos type at all:
T4Number = group
.Where(lg => new int[]{38,40}.Contains(lg.CAUSE) && lg.ANSWERING>0)
.Sum(lg => lg.EN_ TALKINGTIME + lg.EN_ ONHOLDTIME + lg.EN_ ACTIONTIME + lg.UPTIME);

Try without the anonymous type:
var causes = new [] { 38, 40 };
T4Number = group
.Where(lg => causes.Contains(lg.CAUSE) && lg.ANSWERING>0)
.Select(lg => lg.EN_ TALKINGTIME + lg.EN_ ONHOLDTIME + lg.EN_ ACTIONTIME + lg.UPTIME })
.Sum()
This also improves the filter predicate by no longer new-ing the causes each time

Related

Get Group sum not using group.Sum() in linq

The following query works, but I want to get the same result without using grp.Sum(). Can we do it?
from item in (await VehicleReplaceCostDataAsync())
group item by (item.type, item.size, item.ADA, item.eseq) into grp
orderby (grp.Key.eseq, grp.Key.size, grp.Key.ADA)
select new VehicleReplacementCost
{
type = grp.Key.type,
size = grp.Key.size,
ADA = grp.Key.ADA,
count = grp.Sum(x => x.count),
cost = grp.Sum(x => x.cost),
Fcount = grp.Sum(x => x.Fcount),
Fcost = grp.Sum(x => x.Fcost),
eseq = grp.Key.eseq,
}).ToList();
Perhaps by using .Aggregate()? [docs]
count = grp.Aggregate(0, (a, b) => a + b.count)
Thanks for the answer from Astrid. It looks like a good one, but I didn't test it. My colleague gave this solution instead by using yield:
var groups = costs
.GroupBy(type => (type.SystemId, type.Type, type.Size, type.ADA, type.Eseq))
.OrderBy(group => (group.Key.SystemId, group.Key.Eseq, group.Key.Size, group.Key.ADA));
foreach (var group in groups)
{
var result = new ProgramGuideVehicleCostRow
{
SystemId = group.Key.SystemId,
Type = group.Key.Type,
Size = group.Key.Size,
ADA = group.Key.ADA,
};
foreach (var row in group)
{
result.Cost += row.Cost;
result.Fcost += row.Fcost;
result.Count += row.Count;
result.Fcount += row.Fcount;
}
yield return result;
}

How to group and count missing values using linq

How do I go about counting missing values using linq. Basically I am counting occurrences within a particular month and I want the count to show as zero if there were no entries for that particular month.
However, currently if there are no entries for that month the array skips a month as shown at index 5 below. The reason I don't want this to happen is because I am plotting the results on a chart so the skipped dates are out of sync from index 5 onwards with the actual count.
Below is my linq query
var veterans = _db.Records
.Where(j => j.Requestor == "Veterans" && EF.Functions.DateDiffMonth(j.Request_Date, DateTime.Now) >= 0 && EF.Functions.DateDiffMonth(j.Request_Date, DateTime.Now) <= 24)
.GroupBy(g => new { g.Request_Date.Value.Year, g.Request_Date.Value.Month }).OrderBy(d => d.Key.Year).ThenBy(d => d.Key.Month)
.Select(group => new
{
Dates = group.Key,
Count = group.Count()
});
var veteransCount = veterans.Select(n => n.Count).ToArray();
You can create a helper function to generate the month+year enumeration you need:
public static IEnumerable<(int Year,int Month)> MonthsInYears(int fromYear, int fromMonth, int toYear, int toMonth) {
for (int year = fromYear; year <= toYear; ++year)
for (int month = (year == fromYear ? fromMonth : 1); month <= (year == toYear ? toMonth : 12); ++month)
yield return (year, month);
}
Then using this, you can create an enumeration of the period:
var veterans = _db.Records
.Where(j => j.Requestor == "Veterans" && EF.Functions.DateDiffMonth(j.Request_Date, DateTime.Now) >= 0 && EF.Functions.DateDiffMonth(j.Request_Date, DateTime.Now) <= 24)
.GroupBy(g => new { g.Request_Date.Value.Year, g.Request_Date.Value.Month }).OrderBy(d => d.Key.Year).ThenBy(d => d.Key.Month)
.Select(group => new {
YearMonth = group.Key,
Count = group.Count()
});
var minYearMonth = veterans.Select(v => v.YearMonth).First();
var maxYearMonth = veterans.Select(v => v.YearMonth).Last();
var monthsInYears = MonthsInYears(minYearMonth.Year, minYearMonth.Month, maxYearMonth.Year, maxYearMonth.Month);
Then you can GroupJoin (as a left join) to your database data:
var veteransCount = monthsInYears.GroupJoin(
veterans,
ym => new { ym.Year, ym.Month },
v => v.YearMonth,
(ym, sj) => sj.FirstOrDefault()?.Count ?? 0)
.ToArray();
Alternatively, since this is a specific case, you could create a Dictionary for your source data and lookup each enumeration value:
var veteransMap = veterans.ToDictionary(v => v.YearMonth, v => v.Count);
var veteransCount2 = monthsInYears.Select(ym => veteransMap.TryGetValue(new { ym.Year, ym.Month }, out var count) ? count : 0)
.ToArray();
NOTE: If you want the full beginning and ending years, you could just call the MonthsInYears method with 1 and 12 for the from and to months.

I have some code that I would like to turn to linq

I have this piece of code where highAmtCtrList is a list of Outstanding contracts that have to be updated and comCtrList is a list of Dilution contracts from which I update highAmtCtrList.
So, for each conctract in highAmtCtrList, if I find a matching contract in comCtrList, I update it with the amount returned from comCtrList.
The code works, it's just that I would like to change it to linq.
Any ideas.
tks in advance.
Rui Martins
foreach (Outstanding outCtr in highAmtCtrList)
{
Dilution dilCtr =
comCtrList.FirstOrDefault(dil => dil.Contract == outCtr.Contract);
if (dilCtr != null) outCtr.Amount += dilCtr.Amount;
}
Your code looks fine. You can write all this in one line, but IMO it's a less maintainable code:
outCtr.Join(comCtrList,
o => o.Contract,
i => i.Contract,
(o, i) => o.Amount += i.Amount);
EDIT: to sum only first matches:
outCtr.ForEach(o => o.Amount += comCtrList
.Where(i => i.Contract == o.Contract)
.Select(i => i.Amount)
.FirstOrDefault());
How about this?
foreach (Outstanding o in highAmtCtrList)
{
o.Amount += comCtrList.Where(d => d.Contract == o.Contract)
.Select(d => d.Amount)
.FirstOrDefault();
}
Here's another alternative:
foreach (Outstanding o in highAmtCtrList)
{
o.Amount += comCtrList.Where(d => d.Contract == o.Contract)
.Take(1)
.Sum(d => d.Amount);
}

Error trying to exclude records with a JOIN to another object

In my code below, is there any way I can use the results in the object 'WasteRecordsExcluded' to join with searchResults, essentially excluding the WasteId's I don't want.
If I debug to the last line I get the error :
base {System.SystemException} = {"The query contains references to items defined on a different data context."}
Or if joining is impossible then i could change bHazardous from TRUE to FALSE and FALSE to TRUE and do some kind of 'NOT IN' comparison.
Going bananas with this one, anyone help? Kind Regards :
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults;
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var WasteRecordsExcluded = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we);
// Now join the 2 object to eliminate all the keys that do not apply
results = results.Where(n => WasteRecordsExcluded.All(t2 => n.WasteId == t2.Key.wasteid));
}
return results;
Maybe something like this:
.....
var results = searchResults.ToList();
.....
.....
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we).ToList();
.....

LINQ Join Errors

I'm getting the following error:
The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.
when using the code below
var ccrCodes = (from c in db.CCRCodes
join i in items on
new { c.baan_cat_fam_code, c.baan_cat_code } equals
new { i.baan_cat_family_code, i.baan_cat_code }
where i => i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month
select c).Distinct().OrderBy(c => c.code_desc);
What I'm trying to do in LINQ is create a multi-condition join and am running into problems. Any ideas?
Thanks,
Try giving names to the properties in your anonymous objects:
var ccrCodes = (from c in db.CCRCodes
join i in items on
new { FamCode = c.baan_cat_fam_code, CatCode = c.baan_cat_code } equals
new { FamCode = i.baan_cat_family_code, CatCode = i.baan_cat_code }
where i => i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month
select c).Distinct().OrderBy(c => c.code_desc);
EDIT: Alright, I have to confess, I am no expert on query syntax, but you want to filter the 'items' list before doing the join, like the following fluent version of your query:
db.CCRCodes
.Join(
items.Where(i => i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month),
x => new { FamCode = x.baan_cat_fam_code, CatCode = x.baan_cat_code },
x => new { FamCode = x.baan_cat_family_code, CatCode = x.baan_cat_code },
(o,i) => o
).Distinct().OrderBy(c => c.code_desc)
ANOTHER EDIT: Per Ahmad's suggestion:
var ccrCodes = (from c in db.CCRCodes
join i in items.Where(x => x.contact_dt.Value.Year == date.Year && x.contact_dt.Value.Month == date.Month) on
new { FamCode = c.baan_cat_fam_code, CatCode = c.baan_cat_code } equals
new { FamCode = i.baan_cat_family_code, CatCode = i.baan_cat_code }
select c).Distinct().OrderBy(c => c.code_desc);
YET ANOTHER EDIT: Per another Ahmad suggestion:
var ccrCodes = (from c in db.CCRCodes
from i in items
where i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month
&& c.baan_cat_fam_code == i.baan_cat_family_code && c.baan_cat_code == i.baan_cat_code
select c).Distinct().OrderBy(c => c.code_desc);

Resources