Why doesn't Dictionary have AddRange?
标题足够基本,为什么我不能:
1 2 | Dictionary<string, string> dic = new Dictionary<string, string>(); dic.AddRange(MethodThatReturnAnotherDic()); |
对原始问题的评论很好地总结了这一点:
because no one ever designed, specified, implemented, tested, documented and shipped that feature. - @Gabe Moothart
号
为什么?嗯,可能是因为合并字典的行为不能以符合框架指南的方式进行推理。
添加一组键值对,甚至合并两个字典的行为是直接的。但是,如何处理多个重复条目的行为则不是。
当处理重复项时,该方法的行为应该是什么?
我至少可以想到三种解决方案:
当抛出异常时,原始字典的状态应该是什么?
作为一个API使用者,必须迭代地删除重复的元素会很麻烦,这意味着
然后选择归结为:
有支持这两个用例的参数。为此,您是否在签名中添加了
现在,您有了一个标志,它允许
总结
由于在处理重复项时没有清晰、一致和预期的行为,因此更容易不一起处理它们,也不提供开始的方法。
如果您发现自己不断地需要合并字典,那么您当然可以编写自己的扩展方法来合并字典,这将以适合您的应用程序的方式运行。
我找到了另一种解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Dictionary<string, string> mainDic = new Dictionary<string, string>() { {"Key1","Value1" }, {"Key2","Value2.1" }, }; Dictionary<string, string> additionalDic= new Dictionary<string, string>() { {"Key2","Value2.2" }, {"Key3","Value3" }, }; mainDic.AddRangeOverride(additionalDic); // Overrides all existing keys // or mainDic.AddRangeNewOnly(additionalDic); // Adds new keys only // or mainDic.AddRange(additionalDic); // Throws an error if keys already exist // or if (!mainDic.ContainsKeys(additionalDic.Keys)) // Checks if keys don't exist { mainDic.AddRange(additionalDic); } |
。
…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | namespace MyProject.Helper { public static void AddRangeOverride<TKey, TValue>(this Dictionary<TKey, TValue> dic, Dictionary<TKey, TValue> dicToAdd) { dicToAdd.ForEach(x => dic[x.Key] = x.Value); } public static void AddRangeNewOnly<TKey, TValue>(this Dictionary<TKey, TValue> dic, Dictionary<TKey, TValue> dicToAdd) { dicToAdd.ForEach(x => { if (!dic.ContainsKey(x.Key)) dic.Add(x.Key, x.Value); }); } public static void AddRange<TKey, TValue>(this Dictionary<TKey, TValue> dic, Dictionary<TKey, TValue> dicToAdd) { dicToAdd.ForEach(x => dic.Add(x.Key, x.Value)); } public static bool ContainsKeys<TKey, TValue>(this Dictionary<TKey, TValue> dic, IEnumerable<TKey> keys) { bool result = false; keys.ForEachOrBreak((x) => { result = dic.ContainsKey(x); return result; }); return result; } public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) { foreach (var item in source) action(item); } public static void ForEachOrBreak<T>(this IEnumerable<T> source, Func<T, bool> func) { foreach (var item in source) { bool result = func(item); if (result) break; } } } |
玩得高兴。
我的猜测是,对于发生的事情,没有适当的输出给用户。由于字典中不能有重复键,因此如何处理在某些键相交的地方合并两个字典?当然,你可以说:"我不在乎",但这违反了返回错误/抛出重复键例外的惯例。
如果有人像我一样遇到这个问题-可以使用IEnumerable扩展方法实现"addrange":
1 2 3 4 5 | var combined = dict1.Union(dict2) .GroupBy(kvp => kvp.Key) .Select(grp => grp.First()) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); |
。
组合字典的主要技巧是处理重复的键。在上面的代码中,它是
你可以这样做
1 2 3 4 5 6 7 8 | Dictionary<string, string> dic = new Dictionary<string, string>(); // dictionary other items already added. MethodThatReturnAnotherDic(dic); public void MethodThatReturnAnotherDic(Dictionary<string, string> dic) { dic.Add(.., ..); } |
或者使用addrange的列表和/或使用上面的模式。
1 | List<KeyValuePair<string, string>> |
号
请随意使用如下扩展方法:
1 2 3 4 5 6 7 | public static Dictionary<T, U> AddRange<T, U>(this Dictionary<T, U> destination, Dictionary<T, U> source) { if (destination == null) destination = new Dictionary<T, U>(); foreach (var e in source) destination.Add(e.Key, e.Value); return destination; } |
号
如果您正在处理一个新的字典(并且您没有要丢失的现有行),则可以始终使用另一个对象列表中的toDictionary()。
因此,在您的情况下,您可以这样做:
1 2 | Dictionary<string, string> dic = new Dictionary<string, string>(); dic = SomeList.ToDictionary(x => x.Attribute1, x => x.Attribute2); |
如果你知道你不会有重复的钥匙,你可以这样做:
1 | dic = dic.Union(MethodThatReturnAnotherDic()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); |
如果存在重复的键/值对,它将引发异常。
我不知道为什么这不在框架中;应该是。没有不确定性;只是抛出一个例外。对于此代码,它确实会引发异常。