从Dictionary<Key, Item>中删除元素

15
我有一个字典,其中的项是(例如):
  1. "A",4
  2. "B",44
  3. "bye",56
  4. "C",99
  5. "D",46
  6. "6672",0
我还有一个列表:
  1. "A"
  2. "C"
  3. "D"
我想从我的字典中删除所有键不在我的列表中的元素,并且最终我的字典将是:
  1. "A",4
  2. "C",99
  3. "D",46
该怎么做?
4个回答

27

构造一个新的字典以包含列表中的元素会更简单:

List<string> keysToInclude = new List<string> {"A", "B", "C"};
var newDict = myDictionary
     .Where(kvp=>keysToInclude.Contains(kvp.Key))
     .ToDictionary(kvp=>kvp.Key, kvp=>kvp.Value);

如果修改现有的字典很重要(例如,它是某个类的只读属性)

var keysToRemove = myDictionary.Keys.Except(keysToInclude).ToList();

foreach (var key in keysToRemove)
     myDictionary.Remove(key);

注意调用ToList()方法-将键的列表实物化是很重要的。如果您尝试在没有实物化keysToRemove的情况下运行代码,则可能会出现异常,指出类似“集合已更改”的内容。


两种方式的利弊是什么? - guiomie
@ guiomie以前的方法构建新字典,因此您可以保留旧字典,但代价是增加了内存占用。后者在原地修改现有字典。简而言之,如果您不处理非常大的字典,则没有优缺点-这两种方式之间程序状态不等效。 - J0HN
@J0HN 两者都会增加内存占用,因为Except()方法的实现会实例化一个内部数据结构(通常是哈希集)以便能够在O(n)时间内执行操作。 - tigrou

8
// For efficiency with large lists, for small ones use myList below instead.  
var mySet = new HashSet<string>(myList);

// Create a new dictionary with just the keys in the set
myDictionary = myDictionary
               .Where(x => mySet.Contains(x.Key))
               .ToDictionary(x => x.Key, x => x.Value);

你不觉得创建一个新字典可能效率低下吗? - Nick
现在这是一个好问题,什么更有效率,创建一个新的字典还是取出一些项目。我猜这取决于涉及的数字,测量它会很有趣。 - Robert
@YoryeNathan 嗯?O(nmT(n)),其中n是字典的大小,m是列表的大小,T(n)是函数Remove所需的时间。?我不调用Remove,而且使用了一个集合,因此m是可疑的。并不是说我的代码更快,但最快的可能是下面@J0HN的解决方案,myDictionary.Keys.Except(myList).ToList().ForEach(x => myDictionary.Remove(x)); - Joachim Isaksson
抱歉,我被别人的带有“Remove”的答案搞混了。我的答案也没有“Remove”。根据对J0HN的解决方案进行的测试,看起来你赢了。你们两个应该知道,通常LINQ具有开销并且速度较慢。 - SimpleVar
3
人们会停止不恰当地发布这个链接吗?这并不是过早,也不是“优化”。优化是指您接受代码并微调它以使其运行更快一点。这是一个完全不同的算法问题,而且你甚至不能说这是过早,因为我这里只有OP的问题,我并没有做他的项目。 - SimpleVar
显示剩余5条评论

4
dict.Keys.Except(list).ToList()
    .ForEach(key => dict.Remove(key));

0

代码:

public static void RemoveAll<TKey, TValue>(this Dictionary<TKey, TValue> target,
                                           List<TKey> keys)
{
    var tmp = new Dictionary<TKey, TValue>();

    foreach (var key in keys)
    {
        TValue val;
        if (target.TryGetValue(key, out val))
        {
            tmp.Add(key, val);
        }
    }

    target.Clear();

    foreach (var kvp in tmp)
    {
        target.Add(kvp.Key, kvp.Value);
    }
}

例子:

var d = new Dictionary<string, int>
            {
                {"A", 4},
                {"B", 44},
                {"bye", 56},
                {"C", 99},
                {"D", 46},
                {"6672", 0}
            };

var l = new List<string> {"A", "C", "D"};

d.RemoveAll(l);

foreach (var kvp in d)
{
    Console.WriteLine(kvp.Key + ": " + kvp.Value);
}

输出:

A: 4
C: 99
D: 46

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接