在C#中合并两个或多个词典( 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);
EDIT: 从JaredPar和Jon Skeet那里得到了一个很酷的解决方案,但我正在考虑处理重复键的东西 . 如果发生碰撞,它并不一致 .
20 回答
要么 :
结果是一个联合,其中重复条目“y”获胜 .
这部分取决于你遇到重复的事情 . 例如,你可以这样做:
如果你得到任何重复的密钥,那将会爆炸 .
编辑:如果您使用ToLookup,那么您将获得一个查找,每个键可以有多个值 . 然后,您可以将其转换为字典:
这有点难看 - 而且效率低下 - 但这是在代码方面做到最快的方法 . (诚然,我没有测试过 . )
您当然可以编写自己的ToDictionary2扩展方法(名称更好,但我现在没有时间考虑一个) - 这不是很难做,只是覆盖(或忽略)重复键 . 重要的一点(在我看来)是使用SelectMany,并意识到字典支持迭代其键/值对 .
我会这样做:
简单易行 . 根据this blog post它甚至比大多数循环更快,因为它的底层实现通过索引而不是枚举器(see this answer)访问元素 .
如果存在重复,它当然会抛出异常,因此您必须在合并之前进行检查 .
好吧,我迟到了,但这是我用的 . 如果有多个键(“righter”键替换“lefter”键),它不会爆炸,可以合并多个词典(如果需要)并保留类型(限制它需要一个有意义的默认公共构造函数):
琐碎的解决方案是:
请尝试以下方法
以下适用于我 . 如果有重复项,它将使用dictA的值 .
我很晚才参加派对,也许会遗漏一些东西,但如果要么没有重复的密钥,或者正如OP所说的那样,“如果发生碰撞,只要它是d,哪个值保存到dict就没关系了 . 一致,“这个有什么问题(把D2合并到D1)?
这看起来很简单,也许太简单了,我想知道我是否遗漏了什么 . 这是我在一些代码中使用的,我知道没有重复的密钥 . 不过,我还在测试中,所以如果我忽略了某些东西,我现在很想知道,而不是后来发现 .
这是我使用的辅助函数:
如何添加
params
重载?此外,您应该将它们键入
IDictionary
以获得最大的灵活性 .考虑到performance of dictionary key lookups and deletes,因为它们是哈希操作,并且考虑到问题的措辞是最好的方式,我认为下面是一个完全有效的方法,其他有点过于复杂,恕我直言 .
或者,如果您在多线程应用程序中工作,并且您的字典无论如何都需要线程安全,那么您应该这样做:
然后,您可以将其换行以使其处理字典的枚举 . 无论如何,你正在考虑~O(3n)(所有条件都很完美),因为
.Add()
会在幕后做一些额外的,不必要的但实际上是免费的Contains()
. 我认为它不会好得多 .如果要限制大型集合上的额外操作,则应总结要合并的每个字典的
Count
,并将目标字典的容量设置为该值,这样可以避免以后调整大小的成本 . 所以,最终产品是这样的......请注意,我接受了
IList<T>
这个方法...主要是因为如果你接受了一个IEnumerable<T>
,你已经打开了自己的同一组的多个枚举,如果你从一个字典集合中获取,这可能是非常昂贵的推迟LINQ声明 .根据上面的答案,但添加一个Func参数让调用者处理重复项:
派对现在已经死了,但这里是用户166390的“改进版”,它进入了我的扩展库 . 除了一些细节,我添加了一个委托来计算合并的值 .
@Tim:应该是评论,但评论不允许进行代码编辑 .
注意:我申请了@Andrew Orsich将@ANeves修改为解决方案,因此MergeLeft现在看起来像这样:
我知道这是一个老问题,但是因为我们现在有了LINQ,你可以在这样的单行中完成它
要么
害怕看到复杂的答案,不熟悉C# .
这是一些简单的答案 .
合并d1,d2等字典并处理任何重叠键(以下示例中的"b"):
例1
例2
有关更复杂的方案,请参阅其他答案 .
希望有所帮助 .
使用扩展方法合并 . 当存在重复键时它不会抛出异常,而是用第二个字典中的键替换这些键 .
用法:
您可以跳过/忽略(默认)或覆盖重复项:如果您对Linq性能不过于挑剔,那么Bob就是您的叔叔,但我更喜欢简洁的可维护代码:在这种情况下,您可以删除默认的MergeKind.SkipDuplicates来强制执行呼叫者的选择,让开发人员认识到结果将是什么!
使用
EqualityComparer
进行合并,将项目进行映射以进行比较,以进行不同的值/类型 . 这里我们将从KeyValuePair
(枚举字典时的项目类型)映射到Key
.用法: