为什么词典没有AddRange?
标题足够基本,为什么我不能:
Dictionary<string, string> dic = new Dictionary<string, string>(); dic.AddRange(MethodThatReturnAnotherDic());
对原始问题的评论总结得非常好:
因为从来没有人devise,规定,实施,testing,logging和发运该function。 – @Gabe Moothart
至于为什么? 那么,可能是因为合并字典的行为不能以符合框架指南的方式推理。
AddRange
不存在,因为范围对关联容器没有任何意义,因为数据范围允许重复条目。 例如,如果您有一个IEnumerable<KeyValuePair<K,T>>
该集合不防止重复的条目。
添加键值对的集合,甚至合并两个字典的行为是直接的。 但是,如何处理多个重复条目的行为却不是。
方法处理重复时应该是什么样的行为?
至less有三个我能想到的解决scheme:
- 为第一个重复的条目抛出exception
- 抛出一个包含所有重复条目的exception
- 忽略重复项
当抛出exception时,原始字典的状态应该是什么?
Add
几乎总是作为一个primefaces操作来实现:成功并更新集合的状态,或者失败,并且集合的状态保持不变。 由于AddRange
可能由于重复的错误而失败,保持其行为与Add
一致的方式也是通过在任何重复上抛出exception来使其成为primefaces的,并保持原始字典的状态不变。
作为一个API消费者,需要迭代地去除重复的元素,这意味着AddRange
应该抛出一个包含所有重复值的exception。
然后,select归结为:
- 抛出所有重复的exception,只留下原始字典。
- 忽略重复项并继续。
有支持这两种用例的论据。 要做到这一点,你添加一个IgnoreDuplicates
标志的签名?
IgnoreDuplicates
标志(当设置为true时)也将提供显着的加速,因为底层实现将绕过用于重复检查的代码。
所以现在,你有一个标志允许AddRange
支持这两种情况,但是有一个没有logging的副作用(这是框架devise师真正努力避免的)。
概要
由于在处理重复数据时没有明确的,一致的和预期的行为,因此不容易将它们全部处理在一起,也不提供开始的方法。
如果您发现自己不断地需要合并词典,那么当然可以编写自己的扩展方法来合并词典,这些词典的行为方式可以适用于您的应用程序。
我find了解决办法:
Dictionary<string, string> mainDic = new Dictionary<string, string>() { { "Key1", "Value1" }, { "Key2", "Value2.1" }, }; Dictionary<string, string> addDic = new Dictionary<string, string>() { { "Key2", "Value2.2" }, { "Key3", "Value3" }, }; mainDic.AddRangeOverride(addDic); // Overrides all existing keys // or mainDic.AddRangeNewOnly(addDic); // 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); }
…
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; } } }
玩的开心。
我的猜测是缺乏正确的输出到用户发生了什么事。 由于字典中不能有重复键,所以如何处理将两个字典合并在一起的字典? 当然你可以说:“我不在乎”,但是这违背了返回错误/抛出重复键例外的惯例。
你可以做到这一点
Dictionary<string, string> dic = new Dictionary<string, string>(); // dictionary other items already added. MethodThatReturnAnotherDic(dic); public void MethodThatReturnAnotherDic(Dictionary<string, string> dic) { dic.Add(.., ..); }
或使用列表添加和/或使用上面的模式。
List<KeyValuePair<string, string>>
如果有人像我一样遇到这个问题 – 可以通过使用IEnumerable扩展方法来实现“AddRange”:
var combined = dict1.Union(dict2) .GroupBy(kvp => kvp.Key) .Select(grp => grp.First()) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
结合字典的主要技巧是处理重复键。 在上面的代码中是部分。select.Select(grp => grp.First())
。 在这种情况下,它只需从重复组中的第一个元素,但是如果需要,您可以在其中实现更复杂的逻辑。
如果你正在处理w /一个新的Dictionary(并且你没有现有的行丢失),你总是可以从另一个对象列表中使用ToDictionary()。
所以,就你而言,你会做这样的事情:
Dictionary<string, string> dic = new Dictionary<string, string>(); dic = SomeList.ToDictionary(x => x.Attribute1, x => x.Attribute2);
如果你知道你不会有重复的密钥,你可以这样做:
dic = dic.Union(MethodThatReturnAnotherDic()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
如果有重复的键/值对,它将引发exception。
我不知道为什么这不在框架内; 应该。 没有不确定性 只是抛出一个exception。 在这个代码的情况下,它确实会抛出一个exception。
- Decimal.One,Decimal.Zero,Decimal.MinusOne在.Net中的用途是什么?
- 有没有办法将System.IO.Stream转换为Windows.Storage.Streams.IRandomAccessStream?
- RegexOptions.Compiled如何工作?
- Automapper:更新属性值而不创build新的对象
- .NET Core和.NET Standard Class Library项目types有什么区别?
- 如何在WindowsC ++ / CLI中获取应用程序可执行文件的名称?
- BestPractice – 将string的首字符转换为小写字母
- 当传入另一个对象时,谁应该在IDisposable对象上调用Dispose?
- 随机高斯variables