Sum duplicated objects in an array - c#

I have an unsorted array of objects with CustomerId, ProductId and Count (all ints)
I want to combine records where CustomerId and ProductId match, summing the count.
for example:
CId PId Cnt
1 100 5
1 100 1
2 100 7
Desired output:
CId PId Cnt
1 100 6
2 100 7
As you can see for the two records for CId 1 & PId 100 have been merged and the count has been summed.
Can this be done with LINQ?
I know it could done with loops but I'm hoping for a more elegant way

Here I have assumed that the class name is Item:
var result = array.GroupBy(x => new { x.CId, x.PId })
.Select(g => new Item { CId = g.Key.CId, PId = g.Key.PId, Cnt = g.Sum(x => x.Cnt) });
Here is a Live Demo

Related

join table and get the record which has minimum value?

I have the following collection Model: Hotel
public class Hotel {
int HotelId {get;set;}
decimal Price {get;set;}
int vendorId {get;set;}
int vendorHotelId {get;set;}
}
The records will be like this
HotelId Price VendorId VendorHotelId
1 100 1 0
2 200 2 0
3 300 1 0
4 400 2 1
If the VendorHotelId is equal to HotelId then I need to select the record which has the cheapest price in LINQ.
I want the result like this
HotelId Price VendorId VendorHotelId
1 100 1 0
2 200 2 0
3 300 1 0
Can anyone help me to solve this query?
You can use a conditional expression to group based on your condition, then get the minimum price from each group, which will be the one hotel if no matching vendorHotelId exists.
var ans = (from h in hotels
let hasVendor = h.vendorHotelId > 0
group h by hasVendor ? h.vendorHotelId : h.HotelId into hg
let hmin = hg.OrderBy(h => h.Price).First()
select new {
HotelId = hmin.HotelId,
Price = hmin.Price,
vendorId = hmin.vendorId
})
.ToList();
Update: Since you seem to be using fluent syntax based on your comment, here is a translation:
var ans2 = hotels.Select(h => new { h, hasVendor = h.vendorHotelId > 0 })
.GroupBy(hv => hv.hasVendor ? hv.h.vendorHotelId : hv.h.HotelId, hv => hv.h)
.Select(hg => hg.OrderBy(h => h.Price).First())
.Select(hmin => new {
HotelId = hmin.HotelId,
Price = hmin.Price,
vendorId = hmin.vendorId
})
.ToList();
NB: Somewhere someone should write an article on the advantages of conditional GroupBy expressions for unusual groupings.

Grouping records that haven't groups values

Please consider this records:
Id Week Value
-----------------------------
1 1 1000
2 1 1200
3 2 800
4 3 1800
5 3 1100
6 3 1000
I want to group records for 4 weeks but we haven't record for week 4.For Example:
Week Count
---------------------
1 2
2 1
3 3
4 0
How I can do this with linq?
Thanks
First you need an array of weeks then this query might help
var weeks = new List<int>{1,2,3,4}
var q = from w in weeks
join rw in (
from r in table
group r by r.Week into g
select new {week = g.Key, count = g.Count()}) on w equals rw.week into p
from x2 in p.DefaultIfEmpty()
select new {w, count = (x2 != null ? x2.count : 0)};
online result in .net fiddle
You can try
var result = Enumerable.Range(1, 4)
.GroupJoin(table,
week => week,
record => record.Week,
(week, records) => new { Week = week, Count = records.Count() });
As suggested by jessehouwing, the Enumerable.Range will return the possible week numbers to be used as left outer keys within the join.
GroupJoin will then accept as parameters
A lambda/delegate/method that returns the left outer key
A lambda/delegate/method that extracts the right key from your table.
A lambda/delegate/method that builds an item of the result.
Regards,
Daniele.

Constructing a linq query to get associations

I have 2 tables, Category and ProductCategory.
A product can have multiple categories:
Category
CategoryIdCategoryName
1
Electronics
2
E-Reader
3
Tablet
ProductCategory
CategoryIdProductId
1
100
2
100
3
100
3
500
1
800
I have a repository set up for Category that has a navigation property to ProductCategory.
I am trying to construct a LINQ query that takes a CategoryId and return me a list of all the
associated Categories + Number of times it is associated (Association being through product).
For example if we take CategoryId 1 (Electronics) from the above example:
We can see that 1 is linked to ProductId 100 and 800 but at the same time ProductId 100 is linked to Categories 2 & 3. We also see that CategoryId 2 is linked one times to ProductId 100 and CategoryId 3 is linked 2 times to ProductIds 100 and 500.
My expected result set would be (excluding the CategoryId of 1 that was passed in)
CategoryIdAssociation(s)
2
1
3
2
But My problem is if I do something like this:
var resultSet = repository.Query()
.Include(pc => pc.ProductCategory)
.Where(c => c.CategoryId == 1).ToList();
the resultSet is only restricted to
CategoryIdProductId
1
100
1
800
but using above LINQ I want to shape the resultSet to:
CategoryIdAssociation(s)
2
1
3
2
Any ideas ?
You're looking for the count of associations which is an aggregate function that you can use directly against a grouped selection from product category.
var results = ProductCategory
.GroupBy(g => g.CategoryId)
.Select(new {
Category = g.Key,
Associations = g.Count()
})
.ToList();

EF Sum between 3 tables

Say we got a Database design like this.
Customer
Id Name
1 John
2 Jack
Order
Id CustomerId
1 1
2 1
3 2
OrderLine
Id OrderId ProductId Quantity
1 1 1 10
2 1 2 20
3 2 1 30
4 3 1 10
How would I create an entity framework query to calculate the total Quantity a given Customer has ordered of a given Product?
Input => CustomerId = 1 & ProductId = 1
Output => 40
This is what I got so far, through its not complete and still missing the Sum.
var db = new ShopTestEntities();
var orders = db.Orders;
var details = db.OrderDetails;
var query = orders.GroupJoin(details,
order => order.CustomerId,
detail => detail.ProductId,
(order, orderGroup) => new
{
CustomerID = order.CustomerId,
OrderCount = orderGroup.Count()
});
I find it's easier to use the special Linq syntax as opposed to the extension method style when I'm doing joins and groupings, so I hope you don't mind if I write it in that style.
This is the first approach that comes to mind for me:
int customerId = 1;
int productId = 1;
var query = from orderLine in db.OrderLines
join order in db.Orders on orderLine.OrderId equals order.Id
where order.CustomerId == customerId && orderLine.ProductId == productId
group orderLine by new { order.CustomerId, orderLine.ProductId } into grouped
select grouped.Sum(g => g.Quantity);
// The result will be null if there are no entries for the given product/customer.
int? quantitySum = query.SingleOrDefault();
I can't check what kind of SQL this will generate at the moment, but I think it should be something pretty reasonable. I did check that it gave the right result when using Linq To Objects.

Linq query help

Is there a way to write a Linq statement to find duplication in Column B, and only find it when Column A has duplicated values then add the value of Column B to the Column where the duplication is found. Any help is appreciated thanks.
RecordID CartID Quantity ProductID
1 11 3 3
2 12 5 6
3 11 6 3
Delete record 3 and add 6 to the Quantity of RecordID 1 so that it becomes:
RecordID CartID Quantity ProductID
1 11 9 3
2 12 5 6
var records = (from i in list
group i by i.CartID into g
select new Item()
{
RecordID = g.Min(o => o.RecordID),
CartID = g.Key,
Quantity = g.Sum(o => o.Quantity),
ProductID = g.Min(o => o.ProductID)
}).ToList();
This sums all the quantity of items with the same CartId creating only the min occurent RecordId and ProductId as you asked. Selecting the min ProductId is something I needed to do to make the query work.
That is why I think you miss some grouping on ProductId...
You did not ask for this, but I think this is what you want (because it makes common sense to not group apples and pears together). (It gives the same result on the sample data provided but for different ProductsIds it will have different results.
var records = (from i in list
group i by new { cartID = i.CartID, prodID = i.ProductID } into g
select new Item()
{
RecordID = g.Min(o => o.RecordID),
CartID = g.Key.cartID,
Quantity = g.Sum(o => o.Quantity),
ProductID = g.Key.prodID
}).ToList();
This groups by CartID and ProductId. Multi-field grouping in Linq is achieved with anonymous types.

Categories