我有一个简单的类:
public class RawBomItem
{
private string material;
private string item;
private string component;
private string quantity;
private string b;
private string spt;
...
}
每个数据成员都有一个属性。
然后我有一个包含这个类实例的列表
private List<RawBomItem> rawBom;
该清单包含7万多个项目。
此时,我想在此列表上运行一个稍微复杂的LINQ查询。
List<string> endProducts = new List<string>(
rawBom.Where(x1 => new List<string>(rawBom.Select(x2 => x2.Component)
.Distinct())
.Contains(x1.Material) && (x1.B != "F"))
.Select(x3 => x3.Material));
查询似乎进入了一个无限循环。(我等了几分钟才把它关掉)
我会把它变成DB来工作,我只是对问题所在感兴趣。
我不知道怎么会有一个无限循环,但你的代码效率非常低
对于rawBom
中的每个项目,您计算不同的组件集,并将它们复制到一个新列表中。因此,在您的列表中有70000个项目时,您将执行70000^2=4900000000次迭代。此外,对于列表中的每一项,您都在再次迭代不同组件的列表。根据您有多少不同的组件,您可以在顶部添加相同数量的迭代。
这是可以改进的:
var components = new HashSet<string>(rawBom.Select(x => x.Component).Distinct());
var endProducts = rawBom.Where(x => components.Contains(x.Material) &&
x.B != "F")
.Select(x => x.Material)
.ToList();
- 我们从主查询中提取不同组件列表的创建,因此我们只需要计算一次,而不是70000次
- 我们使用
HashSet<string>
而不是List<string>
。这将对Contains
的调用从O(n)
更改为O(1)
最终的结果是,您只枚举了两次列表,结果只有140000次迭代。现在将其与原始迭代次数进行比较。
它是一个无限循环,这有点遥不可及。除非你的序列是一个生成器,但这里没有。
你所拥有的是效率低下的代码。
rawBom.Where( // this goes over the 70,000 item collection once
对于你拥有的70000人中的每一个人:
new List<string>(rawBom.Select(x2 => x2.Component).Distinct()) // this goes over the 70,000 collection 3 times (first select, then distinct, then new list)
.Contains // another bunch of accesses depending on how many distinct items there were
.Select(x3 => x3.Material) // iterates over the resulting collection once
因此,毫无疑问,这将是缓慢的。
List<RawBomItem> list = new List<RawBomItem>();
var components = list.Select(x => x.component).Distinct();
var b = new Func<RawBomItem, bool>(x =>
{
return components.Contains(x.Material) && x.B != "F";
});
var v = list.Where(x => b(x)).Select(x1 => x1.material).ToList();
我会稍微简化您的查询。我想这就是你想要的?
List<string> endProducts = rawBom
.Where(x1 => rawBom.Any(x2 => x2.Component == x1.Material) && x1.B != "2")
.Select(x1 => x1.Material).ToList();
这不会为rawBom中的每个项目创建任何额外的列表,但会使用它本身