I am using ASP.NET MVC and have a many-to-many table that as follows:
custID | objID
================
1 2
1 3
2 5
2 2
3 2
Both userID and objID are Foreign Keys linking to other tables. What I would like to do is get the highest count based on objID. The table above will yield the following results:
objID | objName | Price
=======================
2 | Chicken | 10
The custID does not matter in this scenario as I just want to get the objID with the highest count.
I've tried the following but i'm stuck here:
//retrieve many-to-many table
var retrieved = db.Customer.Include(c => c.Objects)
var topID = retrieved.GroupBy(q => q.objID)
.OrderByDescending(g => g.Count())
Should do the trick.
var topID = retrieved.GroupBy(q => q.objID)
.Select(g => new { Id = g.Key, Total = g.Count() })
.OrderByDescending(g => g.Total).First().Id;
List<int> lst = new List<int>() { 1, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 2 };
var count = lst.GroupBy(q => q).OrderByDescending(s => s.Count())
.First().Key;
var lstKeyWithCount lst.GroupBy(i => i).Select(g => new { Key=g.Key,Count=g.Count() });
in lstKeyWithCount variable you get key with count.
in count variable you get most times repeated value.
Related
The tables I included in my query are not included in the query after the groupby.
but if I do a tolist before groupby, the problem is solved, but it didn't seem like a very good solution. Is it possible for me to solve this problem in a different way?
[HttpGet]
public async Task<IActionResult> GetMostPurchased()
var mostRequestUsers = await dbContext.UserProducts
.Include(x => x.Products).Include(x => x.User)
.GroupBy(x => new { x.UserId, x.ProductId })
.Select(g => new
{
MostPurchased = g.Key.ProductId,
UserId = g.Key.UserId,
Count = g.Count(),
// how can i get the following data fields? After grouping, I cannot access the
"UserProducts" and "Products" table.
ProductName = g.Select(x => x.Product.Name),
ProductPrice = g.Select(x => x.Product.Price),
ProductDesc = g.Select(x => x.Product.Desc),
UserFirstName = g.Select(x => x.User.UserFirstName),
UserLastName = g.Select(x => x.User.UserLastName ),
UserPhoneNumber = g.Select(x => x.User.UserPhoneNumber)
//
})
.GroupBy(x => x.UserId)
.Select(g => g.OrderByDescending(t => t.Count).First());
return mostRequestUsers;
// UserProducts
ID UserId ProductId
1 10 1
2 10 2
3 10 3
4 11 4
5 11 5
6 11 6
6 11 4
6 11 3
6 11 2
6 12 1
6 12 4
6 12 5
// User
ID FirstName LastName
1 Tom Jack
2 Brad Pitt
3 John Rock
// Product
ID ProductName Price
1 Apple 20
2 Dell 30
3 Lenovo 40
my purpose: I want to list the most purchased products by users by user ID.
UserId: 10, MostPurchased: 1, Count: 2, ProductName: null, ProductPrice : null, UserFirstName: null, UserLastName : null
UserId: 11, MostPurchased: 2, Count: 3, ProductName: null, ProductPrice : null, UserFirstName: null, UserLastName : null
UserId: 12, MostPurchased: 3, Count: 2, ProductName: null, ProductPrice : null, UserFirstName: null, UserLastName : null
Include do not work with GroupBy and can be omitted. Just add needed field to grouping key:
var users = dbContext.User
.GroupBy(x => new { x.UserId, x.CarId, x.Car.Name })
.Select(g => new
{
UserId = g.Key.UserId,
CarId = g.Key.CarId,
CarName = g.Key.Name
};
Or rewrite query to use Distinct()
var users = dbContext.User
.Select(x => new
{
x.UserId,
x.CarId,
CarName = x.Car.Name
})
.Distinct();
I'm writing a method that selects customer records based on a group by with the most recent purchase total equal (passed to the method).
I did some search and nothing showed up that helps me to achieve the desired output.
customerList.GroupBy(x=> x.CustomerID },
(key, result) =>
{
var orderedList = result.OrderByDescending(c => c.Date).ToList();
return new Customer
{
CustomerID = orderedList.First().CustomerID,
PurchaseID = orderedList.First().PurchaseID,
Price = orderedList.First().Price,
};
});
CUSTOMERID
PURCHACEID
PRICE
DATE
1
11
235
01-03-2021
1
12
230
01-03-2021
1
14
235
05-04-2021
1
15
535
06-04-2021
1
16
230
07-04-2021
If I'm looking for most recent total purchase price of 1000, I should get
CUSTOMERID
PURCHACEID
PRICE
DATE
1
14
235
05-04-2021
1
15
535
06-04-2021
1
16
230
07-04-2021
You probably need to produce a separate list with the cumulative sums. You can then use TakeWhile to take items until some condition is reached
var list = new[] { 1, 2, 3, 4, 5 };
var sum = 0;
var cummulativeSums = list.Select(v => sum += v).ToList();
var result= list.TakeWhile((_, index) => cummulativeSums[index] < 7).ToList();
// 1, 2, 3
Or you could do it all in one go by creating intermediate pair of values.
var list = new[] { 1, 2, 3, 4, 5 };
var sum = 0;
var result = list.Select(value => (sum += value, value))
.TakeWhile(pair => pair.Item1 < 7)
.Select(pair => pair.value)
.ToList();
I'm trying to check the difference between a master list of items in c# vs an array of lists.
Not quite sure how to build this logic in an efficient way.
Example:
My master list of items is: var MasterOrderIDs = {1,2,3,4}
Then I have an Customer/Order object where it's storing the Customer ID along with its OrderID
CustomerID|OrderID
1 | 1
1 | 2
1 | 3
1 | 4
1 | 5
2 | 1
2 | 2
2 | 3
2 | 4
2 | 5
2 | 6
3 | 2
3 | 3
3 | 4
I want to return an array which has the CustomerID along with the OrderIDs where the difference of the MasterOrderIDs has a difference of less than 2.
Something like:
var OrderDifferences = new Dictionary<int, List<int>>();
So in the case of the Customer/Order, I want to return:
{[1, [5]], [3, [1]}
This is because for CustomerID 1, there is a Order ID 5, which is less than 2 differences. Likewise with CustomerID 3, there is a Order ID 1, which appears in MasterOrderIDs and is less than 2 differences.
How can I create such a check?
Ina real-life scenario I will have big data so wondering what would be the best efficient way of doing it.
Based on the information that we got I can think of two relatively small optimizations. So my disclaimer is that the basic approach is still brute force and maybe there is a smarter way to extract the information but we can still perform some checks in order to exclude some of the uneccessary data.
Small optimization 1
We are looking for Customers who compared to the the master list of orders have one more or one less order at most. In other words, based on your example for
var MasterOrderIDs = {1,2,3,4}
a Customer with 5 orders like customerOrders = { 7, 8, 9, 10, 11 } is still potentially valid but customer with 6 orders customerOrders = { 7, 8, 9, 10, 11, 12 } is not.
The same for the bottom number. A Customer with 3 orders is also potentially valid customerOrders = { 7, 8, 9 } but a customer with less the two orders customerOrders = { 7, 8 } is not.
So based on this we can perform our first small optimization filering customers who have more than MasterOrderIDs.Count() + 2 orders or with less than MasterOrderIDs.Count() - 2
Small optimization 2
Even if we are in the appropriate range of orders we want to make sure that our orderIds overlap. We can allow only 1 order which is present in one of the lists and not present in the other. Basically this is not exactly an optimization, but this is second criteria based on which we can construct our query.
Which is:
First seed some data:
class Order
{
public int CustomerId { get; set; }
public int OrderId { get; set; }
public static List<Order> Seed()
{
return new List<Order>
{
new Order { CustomerId = 1, OrderId = 1},
new Order { CustomerId = 1, OrderId = 2},
new Order { CustomerId = 1, OrderId = 3},
new Order { CustomerId = 1, OrderId = 4},
new Order { CustomerId = 1, OrderId = 5},
new Order { CustomerId = 2, OrderId = 1},
new Order { CustomerId = 2, OrderId = 2},
new Order { CustomerId = 2, OrderId = 3},
new Order { CustomerId = 2, OrderId = 4},
new Order { CustomerId = 2, OrderId = 5},
new Order { CustomerId = 2, OrderId = 6},
new Order { CustomerId = 3, OrderId = 2},
new Order { CustomerId = 3, OrderId = 3},
new Order { CustomerId = 3, OrderId = 4}
};
}
}
Then set the initial data:
var masterList = new List<int> { 1, 2, 3, 4 };
var upperBorder = masterList.Count() + 2;
var bottomBorder = masterList.Count() - 2;
var orders = Order.Seed();
And finally extract the records that we need:
var ordersWithinRange = orders
.GroupBy(o => o.CustomerId)
.Where(x => x.Count() < upperBorder && x.Count() > bottomBorder && x.Select(o => o.OrderId).Except(masterList).Concat(masterList.Except(x.Select(o => o.OrderId))).Count() < 2)
.ToDictionary(d => d.Key, d => d.Select(o => o.OrderId).Except(masterList).Concat(masterList.Except(d.Select(o => o.OrderId))).ToList());
Again. This will take a lot of computing time but I think it's a little bit faster than a sequence of for loops filtering one thing at a time.
I want to find the no of integers that are repeated using linq query. for eg my list consists of
var array = new int[]{1,1,1,2,2,2,2,3,3,9,9,16,16};
Now i want to query like i want to get the count of 1 as 3
count of 2 as 4
count of 3 as 2
count of 9 as 2
count of 16 as 2
How can i do that using linq in c#.
Hope you understand my question.
Easy, using LINQ's GroupBy
var numbers = new int[] { 1, 1, 1, 2, 2, 2, 2, 3, 3, 9, 9, 16, 16 };
var counts = numbers
.GroupBy(item => item)
.Select(grp => new { Number = grp.Key, Count = grp.Count() });
Result:
Number Count
1 3
2 4
3 2
9 2
16 2
array.GroupBy(x => x)
.Select(g => new {
Val = x.Key,
Cnt = x.Count()
}
);
Use GroupBy + Count
var groups = array.GroupBy(i => i);
foreach(var group in groups)
Console.WriteLine("Number: {0} Count:{1}", group.Key, group.Count());
Note that you need to add using System.Linq;.
You can use LINQ GroupBy then Count on each group:
var dic = array.GroupBy(x => x)
.ToDictionary(g => g.Key, g => g.Count());
In here, ToDictionary is used so you can access to Dictionary get Count with better performance if you have large list and need to access often:
int count1 = dic[1]; //count of 1
Using Linq:
var NumArray= new int[] { 1, 1, 1, 2, 2, 2, 2, 3, 3, 9, 9, 16, 16 };
var counts = NumArray.GroupBy(item => item)
.Select(a=>new {Number=a.Key,Count =a.Count()});
var array = new int[] {1,1,1,2,2,2,2,3,3,9,9,16,16};
var query = from x in array
group x by x into g
orderby count descending
let count = g.Count()
select new {Value = g.Key, Count = count};
foreach (var i in query)
{
Console.WriteLine("Value: " + i.Value + " Count: " + i.Count);
}
Result will be;
Value: 1 Count: 3
Value: 2 Count: 4
Value: 3 Count: 2
Value: 9 Count: 2
Value: 16 Count: 2
Here is a DEMO.
Please do not respond using lamba. I have found similar threads but still need help.
I am trying to display the names from the employees table that are not employees of the currently selected manager.
My two sql tables are structured like this but this is fake data
Employees:
pk name
1 bob
2 sam
3 greg
4 kip
5 jill
6 kelly
7 chris
ExpenseTeamMembers:
pk expMgrPk empPk
1 7 2
2 7 5
3 7 1
4 3 6
5 3 4
So if the the current selected (mgr variable) is 3 I want to get the names of all empPks in the employees table except for 6, 4. (kelly, kip) Right now unselectedEmps = sam, jill, bob instead of all 5 of other names from the employees table.
var unselectedEmps = (from u in db.employees
join o in db.expenseTeamMembers on u.pk equals o.empPk
where o.expMgrPk != mgr
select u.name).ToList();
lstAvailable.DataSource = unselectedEmps;
After our extended discussion, I think what you want is this.
from u in db.Employees
where !(from e in db.ExpenseTeamMembers
where e.expMgrPk == selectedMgr.pk
select e.empPk).Contains(u.pk)
select u.Name
The problem is that you are doing an inner join when you actually need a left outer join
See this SO question
I have tried the following and it is giving the correct output. Please try it:
List<Employees> emps = new List<Employees>();
emps.Add(new Employees { PK = 1, Name = "bob" });
emps.Add(new Employees { PK = 2, Name = "sam" });
emps.Add(new Employees { PK = 3, Name = "greg" });
emps.Add(new Employees { PK = 4, Name = "kip" });
emps.Add(new Employees { PK = 5, Name = "jill" });
emps.Add(new Employees { PK = 6, Name = "kelly" });
emps.Add(new Employees { PK = 7, Name = "chris" });
List<ExpenseTeamMembers> etm = new List<ExpenseTeamMembers>();
etm.Add(new ExpenseTeamMembers { empPK = 2, ExpMgrPK = 7, PK = 1 });
etm.Add(new ExpenseTeamMembers { empPK = 5, ExpMgrPK = 7, PK = 2 });
etm.Add(new ExpenseTeamMembers { empPK = 1, ExpMgrPK = 7, PK = 3 });
etm.Add(new ExpenseTeamMembers { empPK = 6, ExpMgrPK = 3, PK = 4 });
etm.Add(new ExpenseTeamMembers { empPK = 4, ExpMgrPK = 3, PK = 5 });
var query = from t in
(
from emp in emps
join o in etm on emp.PK equals o.empPK into j
from k in j.DefaultIfEmpty()
select new { Name = k == null ? string.Empty : emp.Name })
where t.Name != string.Empty
select t.Name;