LINQ - How to group by name from nested array - c#

_id:"63624b321e78f38a3d6baf3e"
Taxes
[0] TaxName:CGST
Amount:9.0
[1] TaxName:SGST
Amount:8.0
_id:"63624b321e78f38a3d6baf3e"
Taxes
[1] TaxName:SGST
Amount:8.0
I need to group by tax name and calculate Total CGST, SGST like below
CGST:9.0
SGST:16.0
I have tried to get the grouping as below. I have an object like movie summary where I added the taxes[] and tried to group by tax name. Please let me know how to do this grouping correctly.
movieSummary.Add(new DSMovieSummaryReport
{
MovieId = orderTicket.MovieId,
Taxes= orderTicket.Taxes,
});
var groupByTaxNamesQuery =
from tax in movieSummary
group tax by tax.Taxes into newGroup
orderby newGroup.Key
select newGroup;

Concept: Flatten array
Flatten the Taxes list to combine all the items from the lists into one list via .SelectMany().
Group by TaxName.
Perform total sum for Amount.
Lastly, with .ToList() to materialize the query execution.
var groupByTaxNamesQuery =
from tax in movieSummary.SelectMany(x => x.Taxes)
group tax by tax.TaxName into newGroup
orderby newGroup.Key
select new { TaxName = newGroup.Key, Amount = newGroup.Sum(x => x.Amount) };
var result = groupByTaxNamesQuery.ToList();
Demo # .NET Fiddle
Thanks to #Svyatoslav Danyliv's suggestion, you can achieve in query expression as below:
var groupByTaxNamesQuery =
from ms in movieSummary
from tax in ms.Taxes
group tax by tax.TaxName into newGroup
orderby newGroup.Key
select new { TaxName = newGroup.Key, Amount = newGroup.Sum(x => x.Amount) };
var result = groupByTaxNamesQuery.ToList();
Demo (Full query expression) # .NET Fiddle

With LINQ i would have done something like :
movieSummary
.SelectMany(m => m.Taxes)
.GroupBy(t=>t.TaxeName)
.Select(g=> new Taxe
{
TaxeName = g.Key,
Amount = g.Sum(t => t.Amount)
});

Related

IGrouping does not contain a definition for

I've been looking at other threads here to learn how to do a GroupBy in linq. I am following the EXACT syntax that has worked for others, but, it's not working.
Here's the query:
var results = from p in pending
group p by p.ContactID into g
let amount = g.Sum(s => s.Amount)
select new PaymentItemModel
{
ContactID = g.ContactID, // <--- Error here
Amount = amount
};
pending is a List<T> that contains, among other columns, ContactID and Amount, but those are the only two I care about for this query.
The trouble is, inside the the select new, the g. won't give me any of the columns inside the original list, pending. And when I try, I get:
IGrouping <int, LeadPurchases> does not contain a definition for ContactID, and no extension method blah blah blah...
This is the SQL I am trying to emulate:
SELECT
lp.PurchasedFromContactID,
SUM (lp.Amount)
FROM
LeadPurchases lp
GROUP BY
lp.PurchasedFromContactID
You are grouping on the basis of ContactID, so it should be the Key for the result, So you have to use g.Key instead of g.ContactID; Which means the query should be like the following:
from p in pending
group p by p.ContactID into g
let amount = g.Sum(s => s.Amount)
select new PaymentItemModel
{
ContactID = g.Key,
Amount = amount
};
updates :
If you want to perform grouping based on more than one column then the GroupBy clause will be like this:
group p by new
{
p.ContactID,
p.Field2,
p.Field3
}into g
select new PaymentItemModel()
{
ContactID = g.Key.ContactID,
anotherField = g.Key.Field2,
nextField = g.Key.Field3
};

How to return an object with the number of grouped rows plus the group by field value?

I'm on C#, .NET 4, and using LINQ I need to group all rows in a table, due to a fixed field, returning that groupby field value and the number of each rows grouped thanks to that clause.
The code I wrote is:
var result = (from p in db.MyPersons
group p by new { p.IDPerson } into g
select new
{
IDPerson = g.Key.IDPerson,
Counter = g.Sum(p => p.IDPerson)
});
but it returns IDPerson on both IDPerson and Counter field in the new generated object.
What's the mistake? It seems Sum doesn't sum?
If you want the number of rows in the group use Count instead: (note you don't need an anonymous type either)
var result = (from p in db.MyPersons
group p by p.IDPerson into g
select new
{
IDPerson = g.Key,
Counter = g.Count()
});
Sum would add up all of the IDPerson values in the group - which would return the same value as IDPerson if there were only one item in the group.
If you want to group by more than one column, you can do this:
var result = (from p in db.MyPersons
group p by new{ p.IDPerson, p.Surname} into g
select new
{
IDPerson = g.Key,
Surname=g.Surname,
Counter = g.Count()
});

LINQ Query with GROUP and SUM

Please help me to get my head around querying using LINQ with a GROUP and SUM.
// Query the database
IEnumerable<BestSeller> best_sellers = from bs in (db.MYDATABASE).Take(25)
where bs.COMPANY == "MY COMPANY"
group bs by bs.PRODCODE into g
orderby g.Sum(g.MQTY)
select new BestSeller()
{
product_code = ,
product_description = ,
total_quantity =
};
I wish to:
Take the top 25 items from db.MYDATABASE
Group all the results by bs.PRODCODE
Order it by the sum total for each bs.PRODCODE
Where the company is "MY COMPANY"
Then pipe the data in to my BestSeller() objects
I'm confused, because as soon as I add my group in to the mix, my bs variable becomes useless.
I'm confused, because as soon as I add my group in to the mix, my bs variable becomes useless.
Yes, because you no longer have a single item - you're now processing a sequence of groups of items. You can get at first item for each group, which I assume would be a valid way of getting at the description?
var query = from bs in db.MYDATABASE.Take(25)
where bs.COMPANY == "MY COMPANY"
group bs by bs.PRODCODE into g
orderby g.Sum(x => x.MQTY)
select new BestSeller
{
product_code = g.Key,
product_description = g.First().DESCRIPTION,
total_quantity = g.Sum(x => x.MQTY)
};
Note that without specifying an ordering, "the top 25 items from db.MYDATABASE" makes no sense. "Top" in what way? You may well want:
from bs in db.MYDATABASE.OrderByDescending(x => x.Price).Take(25)
or something similar. Note that if none of those have a company of "MY COMPANY" you'll end up with no results...
Or if you want the top 25 bestsellers, you want the "take" part at the very end:
var query = from bs in db.MYDATABASE
where bs.COMPANY == "MY COMPANY"
group bs by bs.PRODCODE into g
orderby g.Sum(x => x.MQTY) descending
select new BestSeller
{
product_code = g.Key,
product_description = g.First().DESCRIPTION,
total_quantity = g.Sum(x => x.MQTY)
};
var top25 = query.Take(25);

LINQ: adding OrderBy to query

I'm at the finish line for my university project, and I'm kinda stuck at finishing a query.
The working query looks like this:
var Report = from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
};
I would really appreciate it if you can show me, how to Order the results by the given "Quantity" in descending order.
Thanks!
var Report = (from query in Document.Descendants("order")
group query by query.Element("seller").Value into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
})
.OrderByDescending(order => order.Quantity);
Please do this :
var Report = (from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
}).OrderByDescending(x => x.Quantity);
HTH !!!!
(Kudos to LINQ Orderby Descending Query )
The answers by Skippy and Andrei work, but you can also write as
var Report = from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
let qty = qGroup.Sum(p =>int.Parse(p.Element("quantity").Value)).ToString()
orderby qty descending
select new Orders
{
Seller = qGroup.Key,
Quantity = qty
};
if you'd rather keep it all in one syntax.

C# LINQ Query

I have some data in a List of User defined types that contains the following data:
name, study, group, result, date. Now I want to obtain the name, study and group and then a calculation based onthe result and date. The calculation is effectively:
log(result).where max(date) minus log(result).where min(date)
There are only two dates for each name/study/group, so the result from the maximum data (log) minus the result from the minumum date (log). here is what I have tried so far with no luck:
var result =
from results in sortedData.AsEnumerable()
group results by results.animal
into grp
select new
{
animal = results.animal,
study = results.study,
groupNumber = results.groupNumber,
TGI = System.Math.Log(grp.Select(c => c.volume)
.Where(grp.Max(c=>c.operationDate)))
- System.Math.Log(grp.Select(c => c.volume)
.Where(grp.Min(c => c.operationDate)))
};
Anybody any pointers? Thanks.
It isn't entirely clear how the grouping relates to your problem (what sense does it make to extract a property from a range variable after it has been grouped?), but the part you're having difficult with can be solved easily with MaxBy and MinBy operators, such as the ones that come with morelinq.
var result = from results in sortedData.AsEnumerable()
group results by results.animal into grp
select new
{
animal = grp.Key,
study = ??,
groupNumber = ??,
TGI = Math.Log(grp.MaxBy(c => c.operationDate).volume)
- Math.Log(grp.MinBy(c => c.operationDate).volume)
};
Otherwise, you can simulate these operators with Aggregate, or if you don't mind the inefficiency of sorting:
var result = from results in sortedData.AsEnumerable()
group results by results.animal into grp
let sortedGrp = grp.OrderBy(c => c.operationDate)
.ToList()
select new
{
animal = grp.Key,
study = ??,
groupNumber = ??,
TGI = sortedGrp.Last().volume - sortedGrp.First().volume
};
You have a few syntax problems, you cannot use the results parameter after your into grp line. So my initial attempt would be to change your statement like so
var result =
from results in sortedData.AsEnumerable()
group results by new
{
Animal = results.animal,
Study = results.study,
GroupNumber = results.groupNumber
}
into grp
select new
{
animal = grp.Key.Animal,
study = grp.Key.Study,
groupNumber = grp.Key.GroupNumber,
TGI = System.Math.Log(grp.OrderByDescending(c=>c.operationDate).First().volume)
- System.Math.Log(grp.OrderBy(c=>c.operationDate).First().volume)
};

Categories

Resources