我有一个字典,我需要不断更新传入的数据,在解析传入的数据后,我必须检查字典中是否有任何输入数据中没有的条目(解析后的传入数据是一个列表)我需要将它与字典条目一起映射。
为了避免多个循环删除条目,我为字典计数运行了一个递减循环,然后我使用ElementAt获取索引的字典键,然后检查输入数据中是否存在条目,如果没有,则删除列表中的那个条目。我这样做是因为在字典键上运行foreach循环并从中删除会引发异常,因为字典键集合将被修改。
我想明白这样做会对执行时间产生任何影响。我想了解ElementAt操作的顺序是什么。
答案 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中的新条目包含到字典中 - 如果是这样的话,如果你只有一个新的传入数据列表,我不确定新的条目值是什么。