在c#中合并2个或更多字典(Dictionary<TKey, TValue>)的最佳方法是什么?
(像LINQ这样的3.0特性就可以了)。
我正在考虑一个方法签名,如下所示:
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);
or
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(IEnumerable<Dictionary<TKey,TValue>> dictionaries);
关于重复键的处理:在发生冲突的情况下,保存到字典中的值并不重要,只要它是一致的。
基于上面的答案,但添加一个Func-parameter,让调用者处理重复:
public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> dicts,
Func<IGrouping<TKey, TValue>, TValue> resolveDuplicates)
{
if (resolveDuplicates == null)
resolveDuplicates = new Func<IGrouping<TKey, TValue>, TValue>(group => group.First());
return dicts.SelectMany<Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>>(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => resolveDuplicates(group));
}
注意,如果你使用一个名为“Add”的扩展方法,你可以使用集合初始化器来组合尽可能多的字典,就像这样:
public static void Add<K, V>(this Dictionary<K, V> d, Dictionary<K, V> other) {
foreach (var kvp in other)
{
if (!d.ContainsKey(kvp.Key))
{
d.Add(kvp.Key, kvp.Value);
}
}
}
var s0 = new Dictionary<string, string> {
{ "A", "X"}
};
var s1 = new Dictionary<string, string> {
{ "A", "X" },
{ "B", "Y" }
};
// Combine as many dictionaries and key pairs as needed
var a = new Dictionary<string, string> {
s0, s1, s0, s1, s1, { "C", "Z" }
};
using System.Collections.Generic;
using System.Linq;
public static class DictionaryExtensions
{
public enum MergeKind { SkipDuplicates, OverwriteDuplicates }
public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, MergeKind kind = MergeKind.SkipDuplicates) =>
source.ToList().ForEach(_ => { if (kind == MergeKind.OverwriteDuplicates || !target.ContainsKey(_.Key)) target[_.Key] = _.Value; });
}
你可以跳过/忽略(默认)或覆盖副本:如果你对Linq性能不过分挑剔,而是像我一样喜欢简洁的可维护代码:在这种情况下,你可以删除默认的MergeKind。skipduplicate用于强制调用者进行选择,并使开发人员知道结果将是什么!
下面的方法对我有用。如果存在重复项,则使用dictA的值。
public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> dictA, IDictionary<TKey, TValue> dictB)
where TValue : class
{
return dictA.Keys.Union(dictB.Keys).ToDictionary(k => k, k => dictA.ContainsKey(k) ? dictA[k] : dictB[k]);
}