遇到的问题:
在C#中合并2个或更多词典( Dictionary<T1,T2>
)的最佳方法是什么? (像LINQ这样的3.0功能很好)。
我正在考虑以下方法签名:
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);
要么
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(IEnumerable<Dictionary<TKey,TValue>> dictionaries);
编辑:从JaredPar和Jon Skeet得到了一个很酷的解决方案,但是我正在考虑处理重复键的东西。 在发生冲突的情况下,只要保持一致,就可以将哪个值保存到字典中。
解决方案:
解决方案一
这部分取决于您遇到重复时要发生的情况。 例如,您可以执行以下操作:
var result = dictionaries.SelectMany(dict => dict)
.ToDictionary(pair => pair.Key, pair => pair.Value);
如果您有任何重复的密钥,那将会炸毁。
编辑:如果您使用ToLookup,那么您将获得一个查找,该查找每个键可以具有多个值。 然后,您可以将其转换为字典:
var result = dictionaries.SelectMany(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
这有点难看-而且效率低下-但就代码而言,这是最快的方法。 (坦率地说,我还没有测试过。)
您当然可以编写自己的ToDictionary2扩展方法(使用一个更好的名称,但是我现在没有时间考虑)-这样做并不是很难,只需覆盖(或忽略)重复的键即可。 (在我看来)重要的一点是使用SelectMany,并意识到字典支持在其键/值对上进行迭代。
解决方案二
我会这样做:
dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));
简单容易。 根据此博客文章 ,由于其底层实现通过索引而不是枚举器访问元素,因此它比大多数循环还要快(请参阅此答案) 。
如果有重复项,它当然会引发异常,因此您必须在合并之前进行检查。
解决方案三
如果有多个键(“右”键代替“左”键),则不会爆炸,可以合并多个词典(如果需要)并保留类型(但需要一个有意义的默认公共构造函数的限制):
public static class DictionaryExtensions
{
// Works in C#3/VS2008:
// Returns a new dictionary of this ... others merged leftward.
// Keeps the type of 'this', which must be default-instantiable.
// Example:
// result = map.MergeLeft(other1, other2, ...)
public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others)
where T : IDictionary<K,V>, new()
{
T newMap = new T();
foreach (IDictionary<K,V> src in
(new List<IDictionary<K,V>> { me }).Concat(others)) {
// ^-- echk. Not quite there type-system.
foreach (KeyValuePair<K,V> p in src) {
newMap[p.Key] = p.Value;
}
}
return newMap;
}
}
原文链接:http://findmybug.cn/article/merging-dictionaries-in-c-sharp