我有一个简单的课程:
public class RawBomItem
{
private string material;
private string item;
private string component;
private string quantity;
private string b;
private string spt;
...
}
并且每个数据库都有一个属性。
然后我有一个List包含这个类的实例
private List<RawBomItem> rawBom;
列表包含超过70000项。
此时我想在此列表上运行一个复杂的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工作,我只是对可能出现的问题感兴趣。
答案 0 :(得分:9)
我看不出应该有一个无限循环,但你的代码效率极低
对于rawBom
中的每个项目,您计算组件的不同组合并将它们复制到新列表中。因此,如果列表中包含70,000个项目,则执行70.000 ^ 2 = 4,900,000,000次迭代。此外,对于列表中的每个项目,您将再次迭代不同组件的列表。根据您拥有的不同组件数量,您可以在顶部添加相同数量的迭代。
这可以改进:
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();
HashSet<string>
代替List<string>
。这会将Contains
的通话从O(n)
更改为O(1)
。最终结果是您只列举了两次列表,结果只有140,000次迭代。现在将其与原始迭代次数进行比较。
答案 1 :(得分:1)
这是一个无限循环的范围。除非你的序列是generator,否则你不会在这里。
你所拥有的是完全无效的代码。
rawBom.Where( // this goes over the 70,000 item collection once
你所拥有的70,000人中的每一人:
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
毫无疑问,它会变慢。
答案 2 :(得分:0)
我会简化你的查询一点点。我想这就是你想要的?
List<string> endProducts = rawBom
.Where(x1 => rawBom.Any(x2 => x2.Component == x1.Material) && x1.B != "2")
.Select(x1 => x1.Material).ToList();
这不会为rawBom中的每个项目创建任何其他列表,但会自己使用它
答案 3 :(得分:0)
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();