Какой лучший способ объединить 2 или более словарей ( Dictionary<T1,T2>
) в C #? (3.0 функции, такие как LINQ, в порядке).
Я думаю о сигнатуре метода в соответствии с:
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, но я думал о чем-то, что обрабатывает дубликаты ключей. В случае коллизии не имеет значения, какое значение сохранено в dict, если оно согласовано.
c#
dictionary
merge
orip
источник
источник
dicA.Concat(dicB).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
dict1.Concat(dict2).GroupBy(p => p.Key).ToDictionary(g => g.Key, g => g.Last().Value)
dictA.Concat(dictB.Where(kvp => !dictA.ContainsKey(kvp.Key))).ToDictionary(kvp=> kvp.Key, kvp => kvp.Value)
.Ответы:
Это отчасти зависит от того, что вы хотите случиться, если столкнетесь с дубликатами. Например, вы можете сделать:
Это приведет к исключению, если вы получите дубликаты ключей.
РЕДАКТИРОВАТЬ: Если вы используете ToLookup, то вы получите поиск, который может иметь несколько значений на ключ. Затем вы можете преобразовать это в словарь:
Это немного уродливо и неэффективно, но это самый быстрый способ сделать это с точки зрения кода. (Я не проверял это, по общему признанию.)
Конечно, вы можете написать свой собственный метод расширения ToDictionary2 (с лучшим именем, но у меня сейчас нет времени думать о нем) - это не очень сложно сделать, просто перезаписывая (или игнорируя) дублирующиеся ключи. Важным моментом (на мой взгляд) является использование SelectMany и понимание того, что словарь поддерживает итерацию по его парам ключ / значение.
источник
GroupBy
действительно могло бы быть немного более эффективным - но я сомневаюсь, что это было бы важно в любом случае.ToDictionary
вызова метода. Я предпочел бы, чтобы ответ был более простым для более распространенного случая, и я надеюсь, что любой, кому нужен пользовательский компаратор, способен найти соответствующую перегрузку.Я бы сделал это так:
Просто и легко. Согласно этому сообщению в блоге это даже быстрее, чем большинство циклов, поскольку его базовая реализация обращается к элементам по индексу, а не по перечислителю (см. Этот ответ) .
Конечно, он будет выдавать исключение, если есть дубликаты, поэтому вам придется проверить перед слиянием.
источник
dictionaryFrom.ToList().ForEach(x => dictionaryTo[x.Key] = x.Value)
. Таким образом, значения изdictionaryFrom
переопределяют значение для возможно существующего ключа.Это не взрывается, если есть несколько ключей («правильные» ключи заменяют «lefter» ключи), могут объединять несколько словарей (при желании) и сохраняют тип (с ограничением, что для него требуется значимый открытый конструктор по умолчанию):
источник
this T me
словарь был объявлен с использованиемnew Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase)
или чего-то подобного, результирующий словарь не будет сохранять то же поведение.me
aDictionary<K,V>
, то сможете сделатьvar newMap = new Dictionary<TKey, TValue>(me, me.Comparer);
, и вы также избежите дополнительногоT
параметра type.Тривиальное решение будет:
источник
Попробуйте следующее
источник
источник
foreach(var kvp in Message.GetAttachments().Union(mMessage.GetImages()))
Используя его в рабочем коде, если есть какие-либо недостатки, пожалуйста, дайте мне знать! :)IEnumerable<KeyValuePair<TKey, TValue>>
котором равенство определяется равенством ключа и значения (существует перегрузка для учета альтернатив). Это хорошо для цикла foreach, где это все, что необходимо, но в некоторых случаях вам действительно нужен словарь.Я очень опаздываю на вечеринку и, возможно, что-то упускаю, но если либо нет повторяющихся ключей, либо, как говорит ОП, «В случае коллизии не имеет значения, какое значение сохраняется в dict, если оно согласен, "что не так с этим (слияние D2 в D1)?
Это кажется достаточно простым, может быть, слишком простым, интересно, я что-то упустил. Это то, что я использую в некотором коде, где я знаю, что нет повторяющихся ключей. Я все еще на тестировании, поэтому я хотел бы знать сейчас, если я что-то пропускаю, вместо того, чтобы узнать позже.
источник
Следующее работает для меня. Если есть дубликаты, он будет использовать значение dictA.
источник
Вот вспомогательная функция, которую я использую:
источник
if(first == null)
тогда эта логика бесполезна, потому чтоfirst
нетref
и не возвращается. И это не может быть,ref
потому что он объявлен как экземпляр интерфейса; Вам нужно либо удалить проверку ошибок, либо объявить ее как экземпляр класса, либо просто вернуть новый словарь (без метода расширения).Вариант 1. Это зависит от того, что вы хотите сделать, если уверены, что в обоих словарях нет дублирующего ключа. чем вы могли бы сделать:
Примечание. Это приведет к ошибке, если в словарях появятся дубликаты ключей.
Вариант 2. Если у вас есть дубликат ключа, вам придется обрабатывать дубликат ключа с помощью оператора where.
Замечания : он не получит дубликат ключа. если будет какой-либо дубликат ключа, он получит ключ dictionary1.
Вариант 3: если вы хотите использовать ToLookup. тогда вы получите поиск, который может иметь несколько значений на ключ. Вы можете преобразовать этот поиск в словарь:
источник
Как насчет добавления
params
перегрузки?Кроме того, вы должны ввести их как
IDictionary
для максимальной гибкости.источник
Учитывая эффективность поиска и удаления ключевых слов в словаре, поскольку они являются операциями хэширования, и учитывая, что формулировка вопроса была наилучшим способом, я думаю, что приведенный ниже является совершенно корректным подходом, а остальные немного сложнее, ИМХО.
ИЛИ, если вы работаете в многопоточном приложении, и ваш словарь в любом случае должен быть потокобезопасным, вы должны сделать это:
Затем вы можете обернуть это, чтобы оно обрабатывало перечисление словарей. В любом случае, вы смотрите на ~ O (3n) (все условия идеальны), так как они
.Add()
будут делать дополнительное, ненужное, но практически бесплатное,Contains()
за кулисами. Я не думаю, что это становится намного лучше.Если вы хотите ограничить дополнительные операции в больших коллекциях, вы должны суммировать
Count
каждый словарь, который вы собираетесь объединить, и установить емкость целевого словаря равной этому, что позволит избежать более поздних затрат на изменение размера. Итак, конечный продукт примерно такой ...Обратите внимание, что я использовал
IList<T>
этот метод ... в основном потому, что если вы берете в негоIEnumerable<T>
, вы открыли для себя несколько перечислений одного и того же набора, что может быть очень дорогостоящим, если вы получили свою коллекцию словарей из отложенного LINQ. заявление.источник
Основываясь на ответах выше, но добавив Func-параметр, чтобы позволить вызывающей стороне обрабатывать дубликаты:
источник
Вечеринка уже почти умерла, но вот «улучшенная» версия user166390, которая попала в мою библиотеку расширений. Помимо некоторых деталей, я добавил делегата для вычисления объединенного значения.
источник
@Tim: должен быть комментарий, но комментарии не позволяют редактировать код.
Примечание: я применил модификацию @ANeves к решению @Andrew Orsich, поэтому теперь MergeLeft выглядит так:
источник
Dictionary
типов. Могут быть добавлены перегрузки для других типов словаря (ConcurrentDictionary
иReadOnlyDictionary
т. Д.). Я не думаю, что создание нового списка необходимо, и concat необходим лично. Сначала я итерировал массив параметров, затем итерировал каждый KVP каждого словаря. Я не вижу отступления.Dictionary
объект, даже если вы используете метод расширения дляConcurrentDictionary
. Это может привести к трудно прослеживаемым ошибкам.Я знаю, что это старый вопрос, но так как у нас теперь есть LINQ, вы можете сделать это в одной строке, как это
или
источник
mergee
.Страшно видеть сложные ответы, будучи новичком в C #.
Вот несколько простых ответов.
Объединение словарей d1, d2 и т. Д. И обработка любых перекрывающихся ключей (в следующих примерах «b»):
Пример 1
Пример 2
Для более сложных сценариев см. Другие ответы.
Надеюсь, что это помогло.
источник
Вы можете либо пропустить / игнорировать (по умолчанию), либо перезаписать дубликаты: и ваш дядя Боб при условии, что вы не слишком суетливы в отношении производительности Linq, но предпочитаете вместо этого лаконичный обслуживаемый код, как я: в этом случае вы можете удалить стандартный MergeKind.SkipDuplicates, чтобы принудительно применить выбор для звонящего и сделать разработчика осведомленным о том, какие результаты будут!
источник
Обратите внимание, что если вы используете метод расширения под названием «Добавить», вы можете использовать инициализаторы коллекций, чтобы объединить столько словарей, сколько необходимо:
источник
Слияние с использованием метода расширения. Он не выдает исключение при наличии дублированных ключей, но заменяет эти ключи ключами из второго словаря.
Применение:
источник
Упрощенный от использования по сравнению с моим более ранним ответом с использованием bool по умолчанию неразрушающего слияния, если оно существует, или перезаписать полностью, если оно истинно, вместо использования enum. Он по-прежнему соответствует моим собственным потребностям без какого-либо более причудливого кода:
источник
Объединение с использованием
EqualityComparer
сопоставления элементов для сравнения с другим значением / типом. Здесь мы сопоставимKeyValuePair
(тип элемента при перечислении словаря) сKey
.Применение:
источник
или :
Результатом является объединение, где для повторяющихся записей "y" выигрывает.
источник
источник
Версия от @ user166390 ответа с добавленным
IEqualityComparer
параметром для сравнения ключей без учета регистра.источник
источник