什么是linq的大O.where?

时间:2012-03-25 22:47:50

标签: c# linq big-o where

我正在对从列表中过滤掉项目的位置进行一些比较。我不确定直接这样做是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();
 }
}

2 个答案:

答案 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 WhereO(n)子句之前产生整个集合的工作量。

然而,他有一个观点,它取决于产生集合的算法(例如,如果它是一个已经构建的列表,产生列表是nO(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}}之后迭代整个集合。那是因为一旦候选人匹配,就不会重新考虑。