Учитывая performance of dictionary key lookups and deletes, так как они являются хэш-операции, и принимая во внимание формулировку вопроса был лучший путь, я думаю, что ниже вполне обоснованный подход, а остальные немного чрезмерно сложным, ИМХО ,
public static void MergeOverwrite<T1, T2>(this IDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
{
if (newElements == null) return;
foreach (var e in newElements)
{
dictionary.Remove(e.Key); //or if you don't want to overwrite do (if !.Contains()
dictionary.Add(e);
}
}
ИЛИ если вы работаете в многопоточном приложении и ваш словарь должен быть поточно в любом случае, вы должны делать это:
public static void MergeOverwrite<T1, T2>(this ConcurrentDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
{
if (newElements == null || newElements.Count == 0) return;
foreach (var ne in newElements)
{
dictionary.AddOrUpdate(ne.Key, ne.Value, (key, value) => value);
}
}
Вы могли бы затем обернуть это, чтобы сделать его обработать перечисление словарей. Независимо от того, что вы смотрите примерно на ~ O (3n) (все условия являются идеальными), поскольку .Add()
будет делать дополнительный, ненужный, но практически бесплатный, Contains()
за кулисами. Я не думаю, что это становится намного лучше.
Если вы хотите ограничить дополнительные операции над большими коллекциями, вы должны подытожить Count
каждого словаря, который вы собираетесь объединить, и установить емкость целевого словаря для этого, что позволяет избежать более поздней стоимости изменения размера. Таким образом, конечный продукт что-то вроде этого ...
public static IDictionary<T1, T2> MergeAllOverwrite<T1, T2>(IList<IDictionary<T1, T2>> allDictionaries)
{
var initSize = allDictionaries.Sum(d => d.Count);
var resultDictionary = new Dictionary<T1, T2>(initSize);
allDictionaries.ForEach(resultDictionary.MergeOverwrite);
return resultDictionary;
}
Обратите внимание, что я взял в IList<T>
к этому методу ... главным образом потому, что если вы берете в IEnumerable<T>
, вы открыли себя до нескольких нумераций тот же набор, который может быть очень дорогостоящим, если вы получили свою коллекцию словарей из отложенного оператора LINQ.
Несвязанный, но для тех, кто хочет слить только два словаря без повторных проверок ключей, это прекрасно работает: `dicA.Concat (dicB) .ToDictionary (kvp => kvp.Key, kvp => kvp.Value)` – Benjol 2011-12-14 07:31:42
@ Benjol, вы могли бы добавить это в раздел ответа – 2013-09-02 13:54:56
Слияние Clojure в C#: `dict1.Concat (dict2) .GroupBy (p => p.Key) .ToDictionary (g => g.Key, g => g.Last() .Value) ` – Bruce 2015-06-01 04:00:34