Слияние словарей в C #

Я поместил в список https://pypi.python.org/pypi/linked_list_mod/

класс списка с одиночным соединением Python 2.x и 3.x] Он тестируется с CPython 2.7, CPython 3.4, Pypy 2.3.1, Pypy3 2.3.1 и Jython 2.7b2 и поставляется с красивым автоматизированным набором тестов.

Он также включает классы LIFO и FIFO.

Они не являются неизменными, хотя.

439
задан orip 16 November 2008 в 18:28
поделиться

11 ответов

Это частично зависит от того, что Вы хотите произойти при столкновении с дубликатами. Например, Вы могли сделать:

var result = dictionaries.SelectMany(dict => dict)
                         .ToDictionary(pair => pair.Key, pair => pair.Value);

, Который аварийно завершится, если Вы получите кого-либо, делают дубликаты ключа.

РЕДАКТИРОВАНИЕ: при использовании ToLookup тогда, Вы получите поиск, который может иметь несколько значений на ключ. Вы могли затем преобразовывать это в словарь:

var result = dictionaries.SelectMany(dict => dict)
                         .ToLookup(pair => pair.Key, pair => pair.Value)
                         .ToDictionary(group => group.Key, group => group.First());

Это немного ужасно - и неэффективно - но это - самый быстрый способ сделать это с точки зрения кода. (Я не протестировал его по общему признанию.)

Вы могли записать свой собственный дополнительный метод ToDictionary2, конечно (с лучшим именем, но у меня нет времени для размышления о том теперь) - не ужасно трудно сделать, просто перезаписывание (или игнорирование) делают дубликаты ключа. Важный бит (по моему мнению) использует SelectMany и понимает, что словарь поддерживает повторение по своим парам ключ/значение.

284
ответ дан Sarah Vessels 16 November 2008 в 18:28
поделиться

@Tim: должен быть комментарий, но комментарии не позволяют редактировать код.

Dictionary<string, string> t1 = new Dictionary<string, string>();
t1.Add("a", "aaa");
Dictionary<string, string> t2 = new Dictionary<string, string>();
t2.Add("b", "bee");
Dictionary<string, string> t3 = new Dictionary<string, string>();
t3.Add("c", "cee");
t3.Add("d", "dee");
t3.Add("b", "bee");
Dictionary<string, string> merged = t1.MergeLeft(t2, t2, t3);

Примечание: я применил модификацию @ANeves к решению @Andrew Orsich, поэтому MergeLeft теперь выглядит следующим образом:

public static Dictionary<K, V> MergeLeft<K, V>(this Dictionary<K, V> me, params IDictionary<K, V>[] others)
    {
        var newMap = new Dictionary<K, V>(me, me.Comparer);
        foreach (IDictionary<K, V> src in
            (new List<IDictionary<K, V>> { me }).Concat(others))
        {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K, V> p in src)
            {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }
2
ответ дан keni 16 November 2008 в 18:28
поделиться

Я бы сделал это так:

dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));

Просто и легко. Согласно этому сообщению в блоге это даже быстрее, чем большинство циклов, поскольку его базовая реализация обращается к элементам по индексу, а не по счетчику (см. Этот ответ) .

Конечно, при наличии дубликатов будет выдано исключение, поэтому вам придется проверить перед слиянием.

237
ответ дан SIRHAMY 16 November 2008 в 18:28
поделиться

Как насчет того, чтобы добавить params перегрузка?

кроме того, необходимо ввести их как IDictionary для максимальной гибкости.

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<IDictionary<TKey, TValue>> dictionaries)
{
    // ...
}

public static IDictionary<TKey, TValue> Merge<TKey, TValue>(params IDictionary<TKey, TValue>[] dictionaries)
{
    return Merge((IEnumerable<TKey, TValue>) dictionaries);
}
6
ответ дан Bryan Watts 16 November 2008 в 18:28
поделиться

Попробуйте следующий

static Dictionary<TKey, TValue>
    Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> enumerable)
{
    return enumerable.SelectMany(x => x).ToDictionary(x => x.Key, y => y.Value);
}
20
ответ дан mtijn 16 November 2008 в 18:28
поделиться

Тривиальное решение было бы:

using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
    Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
    var result = new Dictionary<TKey, TValue>();
    foreach (var dict in dictionaries)
        foreach (var x in dict)
            result[x.Key] = x.Value;
    return result;
}
45
ответ дан tvanfosson 16 November 2008 в 18:28
поделиться

Обратите внимание, что, если Вы используете дополнительный метод под названием, 'Добавляют', Вы добираетесь для использования инициализаторов набора для объединения как много словарей по мере необходимости как это:

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" }
};
0
ответ дан 22 November 2019 в 22:55
поделиться

Упрощенный от использования по сравнению с моим более ранним ответом с bool значением по умолчанию неразрушающего слияния, если существующий или перезапись полностью, если верный вместо того, чтобы использовать перечисление. Это все еще удовлетворяет моим собственным потребностям без любого более необычного кода, когда-либо требуемого:

using System.Collections.Generic;
using System.Linq;

public static partial class Extensions
{
    public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, bool overwrite = false)
    {
        source.ToList().ForEach(_ => {
            if ((!target.ContainsKey(_.Key)) || overwrite)
                target[_.Key] = _.Value;
        });
    }
}
1
ответ дан 22 November 2019 в 22:55
поделиться

Вот вспомогательная функция, которую я использую:

using System.Collections.Generic;
namespace HelperMethods
{
    public static class MergeDictionaries
    {
        public static void Merge<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
        {
            if (second == null || first == null) return;
            foreach (var item in second) 
                if (!first.ContainsKey(item.Key)) 
                    first.Add(item.Key, item.Value);
        }
    }
}
8
ответ дан 22 November 2019 в 22:55
поделиться
Dictionary<String, String> allTables = new Dictionary<String, String>();
allTables = tables1.Union(tables2).ToDictionary(pair => pair.Key, pair => pair.Value);
17
ответ дан 22 November 2019 в 22:55
поделиться

Это не сработает, если есть несколько ключей («правые» клавиши заменяют «лефтерные»), может объединить несколько словарей (при желании) и сохранить тип (с ограничением, что для этого требуется значимая общедоступная версия по умолчанию. конструктор):

public static class DictionaryExtensions
{
    // Works in C#3/VS2008:
    // Returns a new dictionary of this ... others merged leftward.
    // Keeps the type of 'this', which must be default-instantiable.
    // Example: 
    //   result = map.MergeLeft(other1, other2, ...)
    public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others)
        where T : IDictionary<K,V>, new()
    {
        T newMap = new T();
        foreach (IDictionary<K,V> src in
            (new List<IDictionary<K,V>> { me }).Concat(others)) {
            // ^-- echk. Not quite there type-system.
            foreach (KeyValuePair<K,V> p in src) {
                newMap[p.Key] = p.Value;
            }
        }
        return newMap;
    }

}
97
ответ дан 22 November 2019 в 22:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: