我有这样的课程
public class Category
{
CategoryID
List<Product> ProductList
}
public class Product
{
CategoryID
}
List<Category>
大约15k行,List <Product>
大约40k行。我正在使用像这样的LINQ
CategoryList.ForEach(i =>
{
i.ProductList = ProductList.Where(x => x.CategoryID == i.CategoryID).ToList();
});
我想知道有任何更好的性能。在其他情况下,数据可能会增加或减少
答案 0 :(得分:12)
我认为使用并行性是愚蠢的,当对算法进行简单的更改可以将其加速千倍。假设CategoryID
具有良好的GetHashCode()
实现,与通过列表扫描的O(1)
时间相比,字典/查找的查找时间几乎O(n)
。
两种可能的方法:
假设类别具有唯一ID,您可以使用:
var categoryById = categories.ToDictionary(c => c.CategoryID);
foreach(var product in products)
{
var category = categoryById[product.CategoryID];
category.Products.Add(product);
}
这有运行时O(products.Count + categories.Count)
并使用O(categories.Count)
内存。
如果类别不是以空列表开头,则可能需要创建它。
var productsByCategory = products.ToLookup(product => product.CategoryID);
foreach(var category in categories)
{
category.Products = products[category.CategoryID].ToList();
}
这有运行时O(products.Count + categories.Count)
并使用O(products.Count)
内存。
由于产品通常多于类别,因此这种方法需要更多内存。另一方面,查找可能无需在类别对象中嵌入产品列表。
答案 1 :(得分:5)
您可以使用LINQ的并行实现 - PLINQ。通常PLINQ会提高LINQ的速度,因为它可以更有效地使用所有可用内核。
CategoryList.AsParallel().ForAll(i =>
{
i.ProductList = ProductList.AsParallel.Where(x => x.CategoryID == i.CategoryID).ToList();
});
答案 2 :(得分:4)
您还可以使用GroupJoin
代替多个where
:
https://msdn.microsoft.com/en-us/library/bb397905.aspx
虽然Parallel会为您提供最高nb核心增强功能,但您可以通过GroupJoin获得线性复杂性。
来自@CodesInChaos
如果类别和产品的数量相同,您将获得从二次到线性运行时的加速
答案 3 :(得分:3)
您可以在组织按类别(例如Dictionary<int, List<Product>>
)分组的产品列表时获得效果。然后,您只需按键选择类别的产品列表,而不是在整个产品列表上执行LINQ查询并生成新的子列表。
CategoryList.ForEach(i =>
{
i.ProductList = ProductDict[i.CategoryID];
});
答案 4 :(得分:2)
在测试性能之后,我发现比之前发布的更好的解决方案是:
static List<Category> FilterList(List<Category> list, List<Product> ProductList)
{
Parallel.For(0, list.Count, i =>
{
list[i].ProductList = new List<Product>();
for (int i2 = 0; i2 < ProductList.Count; i2++)
if (ProductList[i2].CategoryID == list[i].CategoryID) list[i].ProductList.Add(ProductList[i2]);
});
return list;
}
然后list = FilterList(list, products);
对于3,500,000
次操作,只需200ms
答案 5 :(得分:2)
实际上,在这种情况下最有效的解决方案是从ProductList创建CategoryList。像这样:
CategoryList = ProductList
.GroupBy(p=>p.CategoryID)
.Select(
g=>
new Category{
CategoryID=g.Key,
ProductList = g.ToList()
}
);
答案 6 :(得分:2)
如果CategoryList已存在,您可以先按CategoryID对产品进行分组,然后将分组的产品加入类别。
var query =
from p in ProductList
group p by p.CategoryID
into grouped
join c in CategoryList
on grouped.Key equals c.CategoryID
select new { c, grouped };
然后使用循环设置Category对象的ProductList字段。
foreach (var item in query)
item.c.ProductList = item.grouped.ToList();