如何按值元素对C# Dictionary<string, List<int>>进行分组并生成目标字典?
实现Dictionary按值元素反向分组的最优方案
咱们先明确下需求场景:现有一个键为字符串、值为整数列表的字典,现在要反向按整数元素分组——把所有包含某个整数的原字典键收集成列表,作为新字典的键;而属于同一组原键的所有整数,收集成列表作为新字典的值。
原始字典定义:
var dict = new Dictionary<string, List<int>> { ["a"] = new List<int>{1,2}, ["b"] = new List<int>{2,3}, ["c"] = new List<int>{4,5} };
期望得到的结果:
var result = new Dictionary<List<string>, List<int>> { [new List<string> { "a"}] = new List<int> { 1 }, [new List<string> { "b"}] = new List<int> { 3 }, [new List<string> { "a", "b"}] = new List<int> { 2 }, [new List<string> { "c"}] = new List<int> { 4, 5 } };
最优实现方案
这里推荐用LINQ + 自定义列表相等比较器的组合,既简洁高效,又能解决列表作为字典键的相等比较问题:
第一步:定义列表内容相等比较器
因为List<string>作为字典键时,默认是引用比较(只有同一实例才会被视为相同键),所以需要自定义一个基于内容比较的相等器:
public class ListEqualityComparer<T> : IEqualityComparer<List<T>> where T : IEquatable<T> { public bool Equals(List<T> x, List<T> y) { if (x == null && y == null) return true; if (x == null || y == null) return false; if (x.Count != y.Count) return false; // 逐元素比较内容 for (int i = 0; i < x.Count; i++) { if (!x[i].Equals(y[i])) return false; } return true; } public int GetHashCode(List<T> obj) { if (obj == null) return 0; // 基于元素内容生成哈希码 int hash = 17; foreach (var item in obj) { hash = hash * 31 + (item?.GetHashCode() ?? 0); } return hash; } }
第二步:用LINQ实现分组逻辑
var result = dict // 1. 展开嵌套集合:把每个整数和它所属的原字典键一一关联 .SelectMany(kv => kv.Value.Select(num => (Num: num, Key: kv.Key))) // 2. 按整数分组,拿到每个整数对应的所有原键(排序保证键集合顺序一致) .GroupBy(item => item.Num, item => item.Key) .Select(g => (Keys: g.OrderBy(k => k).ToList(), Num: g.Key)) // 3. 按键集合分组,把属于同一组原键的整数归到一起 .GroupBy(item => item.Keys, item => item.Num, new ListEqualityComparer<string>()) // 4. 转换为目标字典,传入比较器保证键的内容比较 .ToDictionary(g => g.Key, g => g.ToList(), new ListEqualityComparer<string>());
逻辑解释
- SelectMany:把原字典的嵌套列表“扁平化”,让每个整数都和它的原键形成独立条目,这是处理嵌套集合的核心操作。
- 第一次GroupBy:先按整数分组,得到每个整数对应的所有原键;这里对原键排序很关键,能避免因为原键顺序不同(比如["b","a"]和["a","b"])被当成不同键集合的问题。
- 第二次GroupBy:把拥有相同原键集合的整数归为一组,这里必须传入自定义比较器,否则字典无法识别内容相同的不同列表实例。
- ToDictionary:最终转换为目标字典,同样需要传入比较器确保键的比较逻辑正确。
内容的提问来源于stack exchange,提问作者user3770190
相关产品推荐
相关产品推荐

