使用linq表达式筛选带有键列表的字典

本文关键字:列表 字典 linq 表达式 筛选 使用 | 更新日期: 2023-09-27 18:11:06

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

Dictionary<string,int> AllUsers;

我有一个特定用户的列表。

List<String> Users;

我想过滤第一个字典AllUsers,只包含名字在SpecificUsers列表中的用户。

我已经用循环手工做了一些事情,但我想使用linq表达式,但我对它们不是很熟悉。

提前感谢您的帮助

使用linq表达式筛选带有键列表的字典

可以过滤Users:

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

这样做的主要好处是您使用索引的AllUsers来进行过滤,因此您的总计算复杂性仅取决于Users中的用户数量(Dictionary.Contains为0(1))—naïve方法倾向于Users * AllUsers

如果您希望输出一个字典,只需将上面的.Select(...)替换为

即可。
.ToDictionary(i => i, i => AllUsers[i])

可能行得通

var newdict = AllUsers.Where(x => Users.Contains(x.Key))
                                        .ToDictionary(val => val.Key, val => val.Value);

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

编辑:正如@Rawling所说,在字典上过滤比在列表上过滤更高效。实现这一目标的解决方案存在于@Luaan答案中(我不会像有些人那样复制它)

您可以使用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

结果集合

只有出现在两个集合中的名称才可用

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

可以使用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);
使用<<p> strong>与
 var query =
            from kvp in yourDictionary
            join s in yourList on kvp.Key equals s
            select new { kvp.Key, kvp.Value };

借助以下有用的函数

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;
    }
}

这是IMO的最佳解决方案(对每个键使用单个查找并且不引入闭包):

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