使用Linq表达式根据键列表过滤字典

7

我有一个包含所有用户及其年龄的字典。

Dictionary<string,int> AllUsers;

我有一个特定用户列表。
List<String> Users;

我希望筛选出字典 AllUsers 的那些用户名在 SpecificUsers 列表中的用户。我已经手动循环做了一些事情,但我希望使用 linq 表达式。不过我对它们不是很熟悉。非常感谢您的帮助。

2
你应该在这里展示你的迭代代码(例如 foreach)。此外,ReSharper可以为您完成此操作,并成为一个很好的学习工具。 - Yuck
1
如果有任何答案对您有帮助,请接受它。 - Kamil Budziewski
5个回答

6
可能会起作用。
var newdict = AllUsers.Where(x => Users.Contains(x.Key))
                                        .ToDictionary(val => val.Key, val => val.Value);

它将创建一个新的字典(因为linq是用于查询而不是更新),其中包含来自字典且在Users列表中的所有用户。您需要使用ToDictionary来实际生成字典。

编辑: 正如@Rawling所说,更有效的方法是在字典上过滤而不是在列表上。实现该解决方案的方法在@Luaan的答案中(我不会复制它,因为有些人这样做)


2
为什么要遍历O(1)查找的集合,然后在O(n)查找的集合上调用Contains方法? - Rawling
@Rawling 这取决于两个集合的大小。一般来说,使用字典进行过滤会更高效,但在这种解决方案中可读性更好,我认为。但感谢您指出这一点。 - Kamil Budziewski

6

您可以过滤用户

Users.Where(i => AllUsers.ContainsKey(i)).Select(i => new { User = i, Age = AllUsers[i] });

这样做的主要好处在于你使用索引的AllUsers进行过滤,因此你的计算复杂度仅取决于Users中用户的数量(Dictionary.Contains为O(1))- 而朴素的方法往往是Users * AllUsers
如果你想得到一个输出字典,只需将上面的.Select(...)替换为
.ToDictionary(i => i, i => AllUsers[i])

3
您可以使用join()方法来连接这两个集合。它让我们可以在一行linq代码中获得您需要的结果。
var allUsers    = new Dictionary<string, int>();
allUsers.Add("Bob", 10);
allUsers.Add("Tom", 20);
allUsers.Add("Ann", 30);

var users       = new List<string>();
users.Add("Bob");
users.Add("Tom");
users.Add("Jack");

var result  = allUsers.Join(users, o => o.Key, i => i, (o, i) => o);
foreach(var r in result)
{
    Console.WriteLine(r.Key + " " + r.Value);
}

它将在控制台输出以下内容:
Bob 10
Tom 20

结果集中只有出现在两个集合中的名称才会被包含。


2

有多种方法可以做到这一点

您可以使用 where 关键字来实现

 var result= yourDictionary.Where(p=> yourList.Contains(p.Key))
     .ToDictionary(p=> p.Key, p=> p.Value);

但是如果你有很多条目,最好使用HashSet

var strings = new HashSet<string>(yourList);
var result= yourDictionary.Where(p=> strings.Contains(p.Key))
        .ToDictionary(p=> p.Key, p=> p.Value);

使用JOIN

 var query =
            from kvp in yourDictionary
            join s in yourList on kvp.Key equals s
            select new { kvp.Key, kvp.Value };

0

借助以下有用的函数的帮助

public static class Extensions
{
    public static KeyValuePair<TKey,TValue>? Find<TKey, TValue>(this IDictionary<TKey, TValue> source, TKey key)
    {
        TValue value;
        return source.TryGetValue(key, out value) ? new KeyValuePair<TKey, TValue>(key, value) : (KeyValuePair<TKey, TValue>?)null;
    }
}

这里是我认为最优解(每个键只使用单一查找,不引入闭包):

var filteredUsers = Users.Select(AllUsers.Find)
    .Where(item => item.HasValue)
    .ToDictionary(item => item.Value.Key, item => item.Value.Value);

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