I've been racking by brain all night (again) looking to get the total count of each set of unique items in a list. I was able to get the unique list items. But I can't seem to figure out how to get the count of each group of unique items. Please tell me if this makes sense. Below's my code:
List<string> categories = new List<string>();
foreach (var item in Model)
{
categories.Add(item.Category);
}
IEnumerable<string> distinctCategories = categories.Distinct();
foreach (string category in distinctCategories)
{
#category #category.Count()
}
As you can see, I have a link displayed for each unique item in my Model's "Category" property (Item.Category). Where you see the category count at the end of the link it actually displays the number of characters in the category (such as the number 5 for the category "Rings"). But I really want the number to represent the number of times the category "Rings", for example, is found in the Model's Categories property.
Please help
To get the count, you need to use a GroupBy instead of Distinct:
var distinctCategories =
categories.GroupBy(x => x)
.Select(g => new { Name = g.Key, ItemsCount = g.Count() });
foreach (var category in distinctCategories)
{
#category.Name #category.ItemsCount
}
Related
So I was working on a DropDown list and it works, but it has many duplicate emails, I just want to see distinct emails... So I tried doing .Distinct() in the model class, but that still gave me duplicates..
Model Class:
public string One_Manager_Email{ get; set; }
public List<Hello> getManagers()
{
var que = (from wr in db.View
select new Hello
{
O_Manager_Email= wr.One_Manager_Email
}).Distinct().ToList();
return que;
}
Controller Class: (This is probably where the problem is happening)
public ActionResult Index()
{
test = new Hello();
ViewBag.Managers = new SelectList(test.getManagers(), "", "O_Manager_Email");
return View(test.getStuff());
}
View Class:
<div>
#Html.DropDownList("Managers", ViewBag.Managers as SelectList)
</div>
Any help would be great, thank you!
You need to group your objects by the property you want them to be distinct by, and then select the first element of the grouping.
public List<Hello> getManagers()
{
var que = (from wr in db.View
select new Hello
{
O_Manager_Email= wr.One_Manager_Email
})
.GroupBy(g => g.O_Manager_Email) //group by property
.Select(g => g.First()) //take first element from every grouping
.ToList();
return que;
}
For some more details, you can see this post that has more details on grouping and distinct: LINQ's Distinct() on a particular property
Distinct won't work on objects like that, as objects are always distinct, but you can try using group by in your query, something along these lines:
var que = (from wr in db.View
group new {wr.One_Manager_Email}
by new {wr.One_Manager_Email} into grouped
select new Hello
{
O_Manager_Email= grouped.Key.One_Manager_Email
}).ToList();
return que;
If you just need email address, you can select just string instead of selecting Hello object. If you select Hello object and try to distinct you like that way, you obviously get duplicated items. Because every object is already unique.
I believe you have already answer. GroupBy might solve your problem. However unless you really need GroupBy, don't use GroupBy! It's really expensive operation.
In your case, you should use DistinctBy.
var distinctList = list.DistinctBy(x => x.Prop).ToList();
On your code:
var que = (from wr in db.View
select new Hello
{
O_Manager_Email = wr.One_Manager_Email
}).DistinctBy(x=>x.O_Manager_Email).ToList();
Oh, in terms of DistinctBy usage, you should import namespace of Microsoft.Ajax.Utilities.
using Microsoft.Ajax.Utilities;
I have two tables deal_outlet and vendors_outlet. I am trying to compare a list of outlet_id from deal_outlet table to vendor table but .contain method shows error has some invalid arguments. I really don't understand problem in this code.
public ActionResult Detail_of_deal(int id)
{
var d1 = db.deal_outlet.Where(x => x.outlet_id==id).ToList();
f_model.model4 = db.vendors_outlet.Where(x =>d1.Contains(x.outlet_id)).ToList();
var d = obj.detail_of_image(id,ref model);
return View(f_model);
}
Depending on the goal of the code you could try the following:
public ActionResult Detail_of_deal(int id)
{
var d1 = db.deal_outlet.Where(x => x.outlet_id==id).ToList();
f_model.model4 = db.vendors_outlet.AsEnumerable().Select(x => d1.Contains(x.outlet_id)).ToList();
var d = obj.detail_of_image(id,ref model);
return View(f_model);
}
That should make f_model.model4 a list of all the vendors_outlets that have a matching deal_outlet.id
The Linq Contains method returns true if the list contains the item passed in. You are asking to see if a list of deal_outlet objects contains an int, which obviously it won't.
Instead of projecting a collection of deal_outlets, project a list of integers:
var d1 = db.deal_outlet.Where(x => x.outlet_id==id).Select(x => x.outlet_id);
f_model.model4 = db.vendors_outlet.Where(x =>d1.Contains(x.outlet_id)).ToList();
But logically, that's the same as:
f_model.model4 = db.vendors_outlet.Where(x =>x.outlet_i==id)).ToList();
So it's not clear what you're trying to do.
EDIT
Based on your comments, I believe these are the queries you want:
i am trying to fetch list of outlet_id from deal_outlet table where deal_id equal to id,
var d1 = db.deal_outlet.Where(x => x.deal_id==id).ToList();
Now want to compare this list to vendor_outlet table and fetch those rows where outlet_id from deal_outlet table equals to outlet_id in vendor_outlet table
Get a list of ID's to match:
var ids = d1.Select(x => x.outlet_id).ToList();
And use Contains to see if the list contains any of the IDs from the related table:
f_model.model4 = db.vendors_outlet.Where(vo => ids.Contains(vo.outlet_id))
.ToList();
I have "Products table" with following fields
PID int,
product_name varchar(),
product_price int
"Cart table" with following fields
cart_ID
user_id
PID
So I want to display cart items of logged in user
For example if user_ID=100 is logged in , then only his cart items should be displayed to him, with all the product details.
Am using asp.net with entity framework
public ActionResult Cart()
{
Products pro = new Products();
Cart cart =new Cart();
var productID = db.cartDetails.Where(pid => pid.productId == cart.productId && cart.user_id == session["user_ID"]);
return View(db.productsDetails.Where(pid => pid.productId == productID));
}
Now problem arises, ProductID being var type I cannot compare it with pid => pid.productid.
What I want to do is first get all the product_id's of user from cart table by comparing uid_id (Logged in user) with user_id in cart table, then displaying product details of those product_id's from product Table. So obviously I need to store multiple product_id's,so that i can populate their data on the cart page.
The LINQ expression db.cartDetails.Where(pid=>pid.productId==cart.productId && cart.user_id==session["user_ID"]) would return a collection of cartDetails and not the productId. You must use select to fetch the columns you need, something like this
var productIDs = db.cartDetails
.Where(pid => pid.productId == cart.productId && cart.user_id == session["user_ID"])
.Select(cd => cd.productId)
.ToList();
This would return you a List of productIds. (If you wish to get only one productId, you could use SingleOrDefault or FirstOrDefault depending on your scenario like db.cartDetails.SingleOrDefault(pid => ...).productId).
Also note that you could have used int type for productId instead of using var if you were expecting an integer. Now you are getting a collection type IQueryable<cardDetails> being assigned to productId.
Next you cannot use an equality operator for the returned List anymore, you should check if this list contains the productId from productDetails, something like this:
return View(db.productsDetails.Where(pid => productIDs.Contains(pid.productId)));
Couldn't test this code, but the basic idea is here.
One last thing, consider using a join between the two tables: https://msdn.microsoft.com/en-us/library/bb311040.aspx
Did this and now my cart is working fine
public ActionResult Cart()
List<int> productIDs = new List<int>();
productIDs = db.cartDetails.Where(ch => ch.userId ==12).Select(cd => cd.productId).ToList() ;
List<Products> pDetails = new List<Products>();
for(int i=0;i<productIDs.Count;i++)
{
pDetails.Add(db.productsDetails.Find(productIDs[i]));
}
return View(pDetails);
I have created a set of search results, and I wish to create a filter of available cats, with the number of results within that filter. however I get the most strangest error when trying to do this.
Unable to create a constant value of type 'NAMESPACE.Models.Products'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
this is the code i have tried:
var cats = (from p in ctx1.SubCategories
where myCats.Contains(p.subCategoryId) && p.enabled
select new
AvailableSubCats
{
CategoryName = p.subCategoryName,
Id = p.subCategoryId,
TotalItems = model.Count(x => x.subCategoryId == p.subCategoryId)
}).Distinct();
Products is the object that is called model on the line of totalItems.
I have also tried this:
var cats = from c in ctx1.SubCategories
join p in model on c.subCategoryId equals p.subCategorySubId
group p by c.subCategoryName
into g
select new
AvailableSubCats
{
CategoryName = g.Key,
Id = 0,
TotalItems = g.Count()
};
with the same error, and dont like this because i dont know how to get the name of the category and its ID.
help much appreciated.
thanks
p.s I am using Entity framework 4.1, .net 4 and MVC 3, mysql
in short i am trying to run this in linq, but were the the products side is already a result
select c.*, (select count(productId) from Products where Products.subCategoryId = c.subCategoryId) as counter from SubCategories c
You could try turning your list of products into a list of subCategoryId's so EF can understand it. Something like:
var subCategoryIds = model.Select(m => m.subCategoryId);
var cats = (from p in ctx1.SubCategories
ctx1.SubCategories
where myCats.Contains(p.subCategoryId) && p.enabled
select new
AvailableSubCats
{
CategoryName = p.subCategoryName,
Id = p.subCategoryId,
TotalItems = subCategoryIds.Count(x => x == p.subCategoryId)
}).Distinct();
Given a table of order items (OrderItems) that relates to a table of orders (Orders), which in turn relates to a table of users (Users), is it possible to retrieve all the OrderItems and group them into a dictionary by OrderId with just one query? ie. without performing an iteration over either the OrderItems result set or performing a query for each order.
Desired controller pseudo-code
Dictionary<int,IEnumerable<OrderItem>> OrderItems = DataContext.OrderItems.ToDictionary(Key => oi.OrderId, Value => oi.ToList());
Desired usage:
IEnumerable<OrderItem> currentOrderItems = OrderItems[123]; // where 123 is OrderId
Current Method
In my Controller I presently retrieve a user's orders and order items to pass to the Orders view:
ViewData["Orders"] = (from o in orders
where o.UserId equals CurrentUserId
orderby o.DateCreated descending)
.ToList();
ViewData["OrderItems"] = (from oi in DataContext.OrderItems
join o in DataContext.Orders
on oi.OrderId equals o.OrderId
where o.UserId equals CurrentUserId
select oi)
.ToList();
Then in my view, I retrieve all order items:
IEnumerable<OrderItem> orderItems = ViewData["OrderItems"] as IEnumerable<OrderItem>;
and use LINQ to group and display each order's order items:
IEnumerable<OrderItem> currentOrderItems = orderItems.Where(
i => i.OrderId == order.OrderId
);
This is fairly efficient as only two queries are passed to the database and some processing is done in the view. But ideally, this should be done in the controller.
Solved it! With ToLookup(...)
ViewData["OrderItems"] = (from oi in DataContext.OrderItems
join o in DataContext.Orders
on oi.OrderId equals o.OrderId
where o.UserId == UserId
select oi).ToLookup(oi => oi.OrderId, oi => oi);
And in my view:
ILookup<int,OrderItem> orderItems = ViewData["OrderItems"] as ILookup<int,OrderItem>;
foreach (Order order in orders)
{
DisplayOrder(order);
// Now display this order's items:
foreach(OrderItem item in orderItems[order.OrderId])
{
DisplayOrderItem(item);
}
}
A trace shows only one query to create the lookup.
Looks like I'm making a habit out of answering my own questions...
I think your best bet is to create a method that accepts a lambda for the key and a list to be inserted into the dictionary and then simply enumerates the list and adds to the dictionary using the key provided in the lambda. The method could be an Extension Method of IDictionary and let's call it say, AddRangeWithKeyType()