假设我们有一个List<Product>
,列表中的每个产品都有很多List<Type>
public class Product{
public int Id {get:set;}
public string Name {get:set;}
public List<Type> Types {get;set;}
}
public class Type{
public int Id {get;set;}
public string Name{get;set;}
}
创建产品列表后,我需要按类型对它们进行分组,然后找到属于每种类型的所有内容。我想我应该尝试LINQ
。这是我到目前为止所做的,但似乎不是完成工作的正确方法。可能有人可以帮助我。
var productsList = new List<Product>();
//Adding products and types for each of them
var productTypesList = new Dictionary<int, string>();
foreach (var p in productsList)
{
var pTypes = p.Types;
foreach (var ptype in
pTypes.Where(x=> !productTypesList .ContainsKey(x.Id)))
{
productTypesList.Add(ptype.Id, ptype.Name);
}
}
然后我试图像这样搜索
foreach (var t in productTypesList)
{
var matches = productsList.FindAll(........);
// from here I need to find all the product which belongs to type (t.id)
if (matches.Count > 0)
{
//Do somthing here
}
}
答案 0 :(得分:8)
以下是您想要的:
var productsPerType =
from t in products.SelectMany(
p => p.Types, (p, t) => new { Product = p, TypeId = t.Id })
group t by t.TypeId
into g
select new { g.Key, Products = g.Select(x => x.Product) };
首先,您执行SelectMany
以获取产品内所有类型的列表。对于每种类型,您都会记住类型ID和相应的产品:
from t in products.SelectMany(
p => p.Types, (p, t) => new { Product = p, TypeId = t.Id })
每个t
现在都是一个包含类型ID和产品的匿名对象。接下来,按类型id对这些对象进行分组。现在我们为每种类型的id提供了一组产品。
举个例子,假设您有以下产品和类型:
Product A -- Types 1, 2, 3
Product B -- Types 1
Product C -- Types 1, 3
SelectMany
给出以下中间结果:
1, A
2, A
3, A
1, B
1, C
3, C
我们按类型ID对此结果进行分组,因此我们得到以下组:
1, { A, B, C }
2, { A }
3, { A, C }
这就是你想要的结果。
答案 1 :(得分:2)
var types = (from p in productsList
from t in p.Types
select t).Distinct(new TypeComparerById());
var productsGrouped = (from t in types
select new
{
Type = t,
ProductsPerType = productsList.Where(p=>p.Types.Any(pt=>pt.Id == t.Id))
}).ToList();
修改强>
Ronald Wildenberg正确地指出,只有实例相同时,对Distinct()的调用才会起作用。为了纠正这个问题,我使用以下实现进行更新
public class TypeComparerById : IEqualityComparer<Type>
{
public bool Equals(Type t1, Type t2)
{
if (t1.Id == t2.Id)
{
return true;
}
else
{
return false;
}
}
public int GetHashCode(Type t)
{
return t.Id.GetHashCode();
}
}
你应该选择他的答案是正确的(虽然下一个也是正确的)
答案 2 :(得分:0)
要查找与每种产品类型相关联的产品数量(产品可以有多种类型),您可以先选择所有不同类型的产品
var productTypeEqualityComparer = new ProductTypeEqualityComparer();
var results = productsList.SelectMany(b => b.Types ).Distinct(productTypeEqualityComparer );
然后您可以列出包含每种不同类型的所有产品:
Dictionary<Type, List<Product>> productsByProductType = new Dictionary<Type, List<Product>>()
foreach (Type productType in results)
{
productsByProductType[productType] = productsList.Where(p => p.Types.Contains(productType, productTypeEqualityComparer )).ToList();
}
像这样创建你的相等比较器:
public class ProductTypeEqualityComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y) {
// I'm assuming here that the ID is unique to each type, but if it is
return x.Id == y.Id;
}
public int GetHashCode(Type obj) {
return obj.Id.GetHashCode();
}
}
*编辑添加相等比较器
答案 3 :(得分:-1)
然后我试图像这样搜索
为此你不需要字典......
代码:
var productsList = new List<Product>();
productsList.Add(new Product { Id = 1, Name = "p1", Types = new List<Type>() { new Type() { Id = 1, Name = "ptype1" }, new Type() { Id = 2, Name = "ptype2" } } });
productsList.Add(new Product { Id = 2, Name = "p2", Types = new List<Type>() { new Type() { Id = 1, Name = "ptype1" } } });
productsList.Add(new Product { Id = 3, Name = "p3", Types = new List<Type>() { new Type() { Id = 2, Name = "ptype2" } } });
productsList.Add(new Product { Id = 4, Name = "p4", Types = new List<Type>() { new Type() { Id = 2, Name = "ptype2" }, new Type() { Id = 3, Name = "type3" } } });
// this is an IEnumerable<Type> (types with the same Id and different name will take only the first)
var productTypesList = (from p in productsList // for each product
from t in p.Types // for each type in product
group t by t.Id into types // group em by Id into types
select types.First()); // but use only the first (else this would be an IEnumerable<IGrouping<Type>>
Console.WriteLine("Types:");
//EDIT: Since Francesca had some complains, and thought having a dictionary from this is difficult, here is a one liner to do that.
// This can be done by surrounding the query above with parenthesis and adding the ToDictionary() call at the end
// I prefer not to use a dictionary unless needed and your code seems not to need it since you need to loop on product types, as stated at the end of the question
// Use this only if you need to store or pass around these values. if you do, you loose potential other properties of your types.
var prodTypeDict = productTypesList.ToDictionary(v => v.Id, v => v.Name);
foreach (var p in productTypesList)
{
Console.WriteLine(p.Id + " " + p.Name);
}
foreach (var type in productTypesList)
{
// this is an IEnumerable<Product>
var products = from p in productsList // for each product
where p.Types.Any(t => t.Id == type.Id) // that has this type
select p;
Console.WriteLine("Products of type: " + type.Name);
foreach (var p in products)
{
Console.WriteLine(p.Id + " " + p.Name);
}
}
输出:
Types:
1 ptype1
2 ptype2
3 type3
Products of type: ptype1
1 p1
2 p2
Products of type: ptype2
1 p1
3 p3
4 p4
Products of type: type3
4 p4