Enumerable.ElementAt vs foreach

时间:2010-10-06 11:06:27

标签: c# .net foreach

我有一个字典,我需要不断更新传入的数据,在解析传入的数据后,我必须检查字典中是否有任何输入数据中没有的条目(解析后的传入数据是一个列表)我需要将它与字典条目一起映射。

为了避免多个循环删除条目,我为字典计数运行了一个递减循环,然后我使用ElementAt获取索引的字典键,然后检查输入数据中是否存在条目,如果没有,则删除列表中的那个条目。我这样做是因为在字典键上运行foreach循环并从中删除会引发异常,因为字典键集合将被修改。

我想明白这样做会对执行时间产生任何影响。我想了解ElementAt操作的顺序是什么。

6 个答案:

答案 0 :(得分:7)

如果您需要提供索引语义并且无法保证索引语义在底层枚举中可用,则

ElementAt非常有用。当枚举作用的是IList<T>(包括List和数组)时,它确实使用O(1)索引,但是否则是O(n)*,这使得它在序列中用于所有来自O(n)操作它将是一个列表O(n * n)。

但是,如果您获得了dict.Keys.ToList()的密钥副本,那么您可以安全foreach通过该密钥,因为更改字典不会更改。

不清楚的是,为什么你不只是用新的字典替换旧的字典,这将再次快得多(简单的引用分配)。

*更新:在linq的.NET核心版本中,ElementAt()为O(1)的案例范围更广,例如Select()的结果IList<T> }。此外OrderBy(…).ElementAt(…)现在是O(n)而不是O(n log n),因为组合序列变成了快速选择而不是快速排序,然后是迭代。

答案 1 :(得分:3)

使用“mark then remove”技巧作为解决方法,在迭代时无法修改集合。

var dict = new Dictionary<int, string>
{ 
    {3, "kuku" },
    {1, "zOl"}
};

var newKeys = new List<int> { 1, 2, 4 };

var toRemove = dict.Keys.Except(newKeys).ToList();

foreach (var k in toRemove)
    dict.Remove(k);

答案 2 :(得分:2)

ElementAt()确实使用了枚举器,所以如果你想要最快的索引访问,你应该使用一个数组。当然,这是以固定长度的代价来实现的,但是如果阵列的大小不是经常变化的话,Array.Resize()可能是可行的。

答案 3 :(得分:2)

Except()似乎可以在这里工作:

Dictionary<int, string> dict = new Dictionary<int, string>
{ 
    {3, "kuku" },
    {1, "zOl"}
};

IEnumerable<int> data = new List<int> { 1, 2, 4 };

IEnumerable<int> toRemove = dict.Keys.Except(data);

foreach(var x in toRemove)
    dict.Remove(x);

答案 4 :(得分:1)

我认为ElementAt()使用枚举器来获取所需的元素。

它将与:

相同
object returnedElement = null;
int i = 0;
foreach (var obj in dictionary.Keys)
{
   if (i++ == at)
    {
      returnedElement = obj;
      break;
    }
}

答案 5 :(得分:0)

您可以按如下方式获取目标(词典)和源(列表)中匹配条目的词典:

using System;
using System.Collections.Generic;
using System.Linq;

Dictionary<string, string> target = new Dictionary<string, string>();
List<string> source = new List<string>();
target.Add("a", "this is a");
target.Add("b", "this is b");
source.Add("a");
source.Add("c");

target = Enumerable.Select(target, n => n.Key).
    Where(n => source.Contains(n)).ToDictionary(n => n, k => target[k]);

我不清楚你是否想要将List中的新条目包含到字典中 - 如果是这样的话,如果你只有一个新的传入数据列表,我不确定新的条目值是什么。