我正在对从列表中过滤掉项目的位置进行一些比较。我不确定直接这样做是O(n),还是使用.Where()。关于简单数据集的I made a simple example to test .Where()
。有n = 100个项目,当我在函数BigO()
的行上运行调试器时,它正好100次让我认为.Where()也是O(n)。我无法弄清楚的是在操作过程中存储数据的位置,我不确定这是否会增加任何增加的复杂性。
我错过了什么,或者是.Where()O(n)?
public class ListerFactory
{
public class Lister
{
bool includeItem { get; set; }
}
List<Lister> someList { get; set; }
public ListerFactory()
{
someList = new List<Lister>();
BuildLister();
}
public void BuildLister()
{
for(int i = 0; i < 100; i++)
{
var inc = new Lister();
inc.includeItem = i % 2;
someList.Add(inc);
}
BigO();
}
public void BigO()
{
someList = someList.Where(thisList => thisList.includeItem == true).ToList();
}
}
答案 0 :(得分:31)
Where()
是O(1);它实际上没有做任何工作。
循环遍历Where()
返回的集合是O(n)。 ..
您看到的O(n)是ToList()
的结果,其中是 O(n)。
如果将Where()
查询传递给O(n 2 )算法,您将看到回调执行n 2 次。 (假设算法不在任何地方缓存)
这称为延迟执行。
大多数(如果不是全部)LINQ提供商都是如此; LINQ提供商急切地执行所有呼叫是没有意义的。
对于LINQ to objects,假设源集合的枚举数为O(n)。
如果你正在使用一些比O(n)更糟的迭代的奇怪集合(换句话说,如果它的MoveNext()
比O(1)更差),那么Where()
将受到它的限制。 / p>
更准确地说,枚举Where()
查询的时间复杂度与原始枚举的时间复杂度相同。
同样,我假设回调是O(1) 如果不是,则需要将回调的复杂性乘以原始枚举的复杂性。
答案 1 :(得分:-1)
取决于收集的来源当然。
我不同意@SLaks的算法是O(1)
,因为对Where()
的查询将继续搜索与条件匹配的候选者。从这个意义上说,O(n)
最差的情况是n
Where
在O(n)
子句之前产生整个集合的工作量。
然而,他有一个观点,它取决于产生集合的算法(例如,如果它是一个已经构建的列表,产生列表是n
,O(1)
项目的数量此外,查看是否存在匹配的算法不一定是O(n)
。如果产量算法为O(m)
且匹配算法为O(n*m)
,则时间复杂度为int[] test = new int[] {1,2,3,4,5,6,7,8,9,10,7,5,0,1,5,6};
以整数集合为例:
Where()
如果要返回至少出现两次的所有整数,可以使用test.Where(x => test.Count(y => x == y) >= 2);
子句执行此操作:
O(n^2)
算法将在public IEnumerable<int> GenerateCollection () {
//some very complex calculation, here replaced by a simple for loop
for(int i = 0; i < 150; i++) {
yield return i;
}
}
其次,您还可以使用惰性设置构建集合:
O(n)
然而,您的算法首先生成列表。所以时间复杂度为O(n*m)
。
请注意,如果您在时间复杂性仍为O(n*n*m)
且不 {{1}}之后迭代整个集合。那是因为一旦候选人匹配,就不会重新考虑。