I am looking to find all the dealers in the database that have a duplicate phone number. I then want to list them in a report with all the dealers information. I am having trouble getting my select statement to populate the dealer record attributes.
Such as dealer name address and so fourth. I am thinking it is because of the group by that is limiting it.
var dealers = _db.Dealers
.Where(x => x.Active)
.GroupBy(x => x.Phone)
.Select(x => new { Dealer = x.Key, Phone = x.Count()})
.Where(x => x.Phone > 1);
Edit:
The desired output would be list of each dealer. I want the dealers with the same phone number to appear next to each other. I don't want any records that are not duplicates based on phone number.
Just add the first item in the group to the last Select:
var dealers = _db.Dealers
.Where(x => x.Active)
.GroupBy(x => x.Phone)
.Select(x => new { Dealer = x.Key, Phone = x.Count(), FirstItem = x.First()})
.Where(x => x.Phone > 1);
the result will then have a FirstItem property
Or if you want all the items in a flat list you can apply the Where directly to the grouping:
var dealers = _db.Dealers
.Where(x => x.Active)
.GroupBy(x => x.Phone)
.Where(g => g.Count() > 1);
.SelectMany(g => g) // flat list of Dealers
You're not saying exactly what the expected output and the actual output is, so I don't know what you mean by 'having trouble'. But I spotted one potentially confusing thing:
You're grouping by the Phone (.GroupBy(x => x.Phone)).
So when you do new { Dealer = x.Key, ... the x.Key will refer to the phone number of this group.
Related
What I am trying to do is get the top 10 most sold Vegetables by grouping them by an Id passed by parameter in a function and ordering them by the sum of their Quantity. I don't know how to use SUM or (total) quite yet but I thought I'd post it here seeking help. If you need me offering you anything else I will be ready.
This is my code:
TheVegLinQDataContext db = new TheVegLinQDataContext();
var query =db.OrderDetails.GroupBy(p => p.VegID)
.Select(g => g.OrderByDescending(p => p.Quantity)
.FirstOrDefault()).Take(10);
And this is an image of my database diagram
Group orders by Vegetable ID, then from each group select data you want and total quantity:
var query = db.OrderDetails
.GroupBy(od => od.VegID)
.Select(g => new {
VegID = g.Key,
Vegetable = g.First().Vegetable, // if you have navigation property
Total = g.Sum(od => od.Quantity)
})
.OrderByDescending(x => x.Total)
.Select(x => x.Vegetable) // remove if you want totals
.Take(10);
Since this is not clear that you are passing what type of id as function parameter, I'm assuming you are passing orderId as parameter.
First apply where conditions then group the result set after that order by Total sold Quantity then apply Take
LINQ query
var result = (from a in orderdetails
where a.OrderId == orderId //apply where condition as per your needs
group a by new { a.VegId } into group1
select new
{
group1.Key.VegId,
TotalQuantity = group1.Sum(x => x.Quantity),
group1.FirstOrDefault().Vegitable
}).OrderByDescending(a => a.TotalQuantity).Take(10);
Lamda (Method) Syntax
var result1 = orderdetails
//.Where(a => a.OrderId == 1) or just remove where if you don't need to filter
.GroupBy(x => x.VegId)
.Select(x => new
{
VegId = x.Key,
x.FirstOrDefault().Vegitable,
TotalQuantity = x.Sum(a => a.Quantity)
}).OrderByDescending(x => x.TotalQuantity).Take(10);
I am calculating totals per month for each country. I have managed to group data by country, but I get error
An item with the same key has already been added.
when trying to put monthly totals into inner dictionary:
var totalPerMonth = data.AsEnumerable()
.Select(x => new
{
Date = Convert.ToDateTime(x.ItemArray[0]).ToString("yyyy-MM"),
Country = x.ItemArray[1],
Revenue = x.ItemArray[2]
})
.GroupBy(x => x.Country)
.ToDictionary(x => x.Key, x => x.ToDictionary(p => p.Date,////this is not unique/// p => Convert.ToDouble(p.Revenue)));
how to group it to make Date key unique?
You can either use ToLookup instead of ToDictionary to allow several values for same date.
Or you can use grouping to get unique dates only (assume you want to calculate totals for each month, so use Sum of revenue for each date group dg ):
var totalPerMonth = data.AsEnumerable()
.Select(x => new {
Date = Convert.ToDateTime(x.ItemArray[0]).ToString("yyyy-MM"),
Country = x.ItemArray[1],
Revenue = Convert.ToDouble(x.ItemArray[2]) // convert here
})
.GroupBy(x => x.Country)
.ToDictionary(
g => g.Key,
g => g.GroupBy(x => x.Date).ToDictionary(dg => dg.Key, dg => dg.Sum(x => x.Revenue))
);
Is there some way in linq group By Id, Order By descending and then select top 5 of each grouping? Right now I have some code shown below, but I used .Take(5) and it obviously selects the top 5 regardless of grouping.
Items = list.GroupBy(x => x.Id)
.Select(x => x.OrderByDescending(y => y.Value))
.Select(y => new Home.SubModels.Item {
Name= y.FirstOrDefault().Name,
Value = y.FirstOrDefault().Value,
Id = y.FirstOrDefault().Id
})
You are almost there. Use Take in the Select statement:
var items = list.GroupBy(x => x.Id)
//For each IGrouping - order nested items and take 5 of them
.Select(x => x.OrderByDescending(y => y.Value).Take(5))
This will return an IEnumerable<IEnumerable<T>>. If you want it flattened replace Select with SelectMany
I need to filter a List<Students> into StudentsWitHighestDebts.
The criteria is that only students where ZachetDidNotPass has maximum value and maximum-1 in all List<Students> are included in the result.
var StudentsWitHighestDebts = students
.Where(s => s.ZachetDidNotPass.(some condition))
.OrderBy(s => s.Name)
.ToList();
For example, given a list of students that have ZachetDidNotPass values 0 1 2 5 6 7. The resulting StudentsWitHighestDebts should only contain the students with 7 and 6 values in ZachetDidNotPass.
First option: take 2 highest debts and filter students by ZachetDidNotPass:
var highestDebts = students.Select(s => s.ZachetDidNotPass)
.OrderByDescending(p => p).Take(2).ToArray();
var studentsWitHighestDebts = students
.Where(s => highestDebts.Contains(s.ZachetDidNotPass))
.OrderByDescending(s => s.ZachetDidNotPass).ToList();
Second option - group by ZachetDidNotPass, sort groups by key descending, take top 2 groups and select students from groups
var studentsWitHighestDebts = students.GroupBy(s => s.ZachetDidNotPass)
.OrderByDescending(g => g.Key).Take(2)
.SelectMany(g => g).ToList();
And third option (take students with highest debt and highestDebt - 1)
var highestDebt = students.Max(s => s.ZachetDidNotPass);
var studentsWitHighestDebts = students
.Where(s => s.ZachetDidNotPass == highestDebt || s.ZachetDidNotPass == highestDebt - 1)
.OrderByDescending(s => s.ZachetDidNotPass).ToList();
I have a class (ApplicationHistory) with 3 properties:
ApplicantId, ProviderId, ApplicationDate
I return the data from the database into a list, however this contains duplicate ApplicantId/ProviderId keys.
I want to supress the list so that the list only contains the the earliest Application Date for each ApplicantId/ProviderId.
The example below is where I'm currently at, but I'm not sure how to ensure the earliest date is returned.
var supressed = history
.GroupBy(x => new
{
ApplicantId = x.ApplicantId,
ProviderId = x.ProviderId
})
.First();
All advice appreciated.
Recall that each group formed by the GroupBy call is an IGrouping<ApplicationHistory>, which implements IEnumerable<ApplicationHistory>. Read more about IGrouping here. You can order those and pick the first one:
var oldestPerGroup = history
.GroupBy(x => new
{
ApplicantId = x.ApplicantId,
ProviderId = x.ProviderId
})
.Select(g => g.OrderBy(x => x.ApplicationDate).FirstOrDefault());
You are selecting first group. Instead select first item from each group:
var supressed = history
.GroupBy(x => new {
ApplicantId = x.ApplicantId,
ProviderId = x.ProviderId
})
.Select(g => g.OrderBy(x => x.ApplicationDate).First());
Or query syntax (btw you don't need to specify names for anonymous object properties in this case):
var supressed = from h in history
group h by new {
h.ApplicantId,
h.ProviderId
} into g
select g.OrderBy(x => x.ApplicationDate).First();