如何用C# LINQ筛选Dictionary中匹配指定ID的Person子集?
问题描述
现有以下C#代码定义的集合和类:
集合定义
Dictionary<int, Person[]> peopleSet = new() { { 1, new [] { new Person(11), new Person(22) } }, { 2, new [] { new Person(33), new Person(44), new Person(55) } }, { 3, new [] { new Person(66), new Person(77), new Person(88) } }, }; IEnumerable<int> ages = new [] { 11, 33, 44 };
Person类定义
public class Person { public int Id { get; init; } public Person(int id) { Id = id; } }
需要通过LINQ筛选得到如下结果:
Dictionary<int, Person[]> peopleSetLinq = new() { { 1, new [] { new Person(11) } }, { 2, new [] { new Person(33), new Person(44) } } };
要求:保留原Dictionary的键,仅保留值数组中Id存在于ages集合中的Person对象;若某个键对应的筛选后数组为空,则该键值对不保留。
解决方案
可以通过LINQ的Select和Where组合实现,同时为了提升查找效率,建议先把ages转换成HashSet<int>(HashSet的Contains操作时间复杂度为O(1),比IEnumerable的O(n)更高效)。
代码实现如下:
// 转换为HashSet提升查找性能 var ageSet = new HashSet<int>(ages); var peopleSetLinq = peopleSet // 处理每个键值对,筛选符合条件的Person数组 .Select(kv => new { kv.Key, FilteredPeople = kv.Value.Where(p => ageSet.Contains(p.Id)).ToArray() }) // 排除筛选后数组为空的键值对 .Where(item => item.FilteredPeople.Length > 0) // 转换为目标Dictionary .ToDictionary(item => item.Key, item => item.FilteredPeople);
代码说明
- 转换为HashSet:将
ages转为HashSet<int>,避免每次判断Id是否存在时都遍历整个集合,在ages元素较多时能显著提升性能。 - 处理每个键值对:对原Dictionary中的每个键值对,筛选出
Id在ageSet中的Person对象并转为数组。 - 过滤空数组项:移除筛选后Person数组为空的键值对(比如原键3对应的所有Person都不在
ages中,因此被排除)。 - 转换为目标结构:将处理后的结果转为
Dictionary<int, Person[]>,得到符合需求的最终集合。
内容的提问来源于stack exchange,提问作者user22548444
相关产品推荐
相关产品推荐

