我正在开发一个面向.NET 3.5的C#应用程序。在其中,我有2个类似的词典,其中包含我的应用程序中特定元素集的验证标准。两个词典都有相同的签名。第一个字典具有默认设置,第二个字典包含一些用户定义的设置。
var default_settings = new Dictionary<string, MyElementSettings>();
var custom_settings = new Dictionary<string, MyElementSettings>();
我想将2个词典合并为一个包含两个词典元素的词典。
我遇到的问题是两个词典都可能具有一些相同的键值。我想要的基本规则是将两个字典组合在一起,如果default_settings中已经存在custom_settings中的任何键,则custom_settings值将覆盖default_settings值。我拥有的最佳解决方案只是一个foreach循环,检查其他字典中是否存在密钥,如果不存在,则添加它。
foreach (var item in custom_settings)
{
if (default_settings.ContainsKey(item.Key))
default_settings[item.Key] = item.Value;
else
default_settings.Add(item.Key, item.Value);
}
我已经完成了一些基本的LINQ查询,但我仍在努力学习更高级的东西。我已经看到了一些将合并2个字典的查询,但大多数都涉及将任何元素与重复键分组,或者仅返回仅包含重复键的集合/是否存在将模仿foreach循环行为的LINQ查询或表达式我在用?
答案 0 :(得分:41)
两点:
设置属性值时,如果 关键是在Dictionary中,与之关联的值 该密钥被分配的替换 值。如果钥匙不在 字典,关键和 值被添加到字典中。
所以你的foreach
循环基本上等同于:
foreach (var item in custom_settings)
{
default_settings[item.Key] = item.Value;
}
现在已经非常简洁了,所以我认为LINQ不会那么帮助你。
答案 1 :(得分:8)
这是一个很好的基于Ani答案的扩展方法。
public static class DictionaryExtensionMethods
{
public static void Merge<TKey, TValue>(this Dictionary<TKey, TValue> me, Dictionary<TKey, TValue> merge)
{
foreach (var item in merge)
{
me[item.Key] = item.Value;
}
}
}
答案 2 :(得分:2)
如果你要这么做,那么我建议为字典键编写一个相等比较器:
private class KeyEqualityComparer<T, U> : IEqualityComparer<KeyValuePair<T, U>>
{
public bool Equals(KeyValuePair<T, U> x, KeyValuePair<T, U> y)
{
return x.Key.Equals(y.Key);
}
public int GetHashCode(KeyValuePair<T, U> obj)
{
return obj.Key.GetHashCode();
}
}
然后,只要您需要合并字典,就可以执行以下操作
var comparer = new KeyEqualityComparer<string, MyElementSettings>();
dict1 = dict1.Union(dict2,comparer).ToDictionary(a => a.Key, b => b.Value);
答案 3 :(得分:1)
我认为我最初选择的答案仍然是这个特定案例的最佳答案,我发现自己处于另一个类似的情况,不久前我有2个IEnumerable<>
个对象,我想转换为字典和以类似的方式合并在一起所以我想我会在这里添加该解决方案以帮助将来的某个人。我没有将两者都转换成字典并使用所选答案中的方法,而是找到了一种新的方法。
我实际上在SE-CodeReview上发布了initial solution,实际上有一个建议可以进一步完善它。这是我使用的最终代码:
public Dictionary<String, Foo> Merge(XElement element1, XElement element2)
{
IEnumerable<Foo> firstFoos = GetXmlData(element1); // parse 1st set from XML
IEnumerable<Foo> secondFoos = GetXmlData(element2); // parse 2nd set from XML
var result = firstFoos.Union(secondFoos).ToDictionary(k=>k.Name, v=>v);
return result;
}
public class Foo
{
public String Name { get; }
// other Properties and Methods
// .
// .
// .
public override Boolean Equals(Object obj)
{
if (obj is Foo)
{
return this.Name == ((Foo)obj).Name;
}
return false;
}
}
关键是Foo
必须覆盖Equals()
来定义哪些Foo
对象可以被认为是重复的,定义哪些对象重复的成员也应该是{{1}密钥(在本例中为Dictionary<>
)
如果您无法覆盖Name
中的Equals()
,则另一个选项是使用Foo
和Concat()
代替GroupBy()
Union()
答案 4 :(得分:0)
此版本创建一个新的完整词典,而不是修改一个词典,并将当前词典与提供的词典合并。
/// <summary>
/// Merges the current dictionary with the supplied dictionary into a new dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="current"></param>
/// <param name="keyValuePairs"></param>
/// <returns></returns>
public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> current, IDictionary<TKey, TValue> keyValuePairs)
{
var dictionaryMerge = new Dictionary<TKey, TValue>(current);
foreach (var item in keyValuePairs)
{
dictionaryMerge[item.Key] = item.Value;
}
return dictionaryMerge;
}