Merging dictionaries in C#

前端 未结 26 1037
温柔的废话
温柔的废话 2020-11-22 08:25

What\'s the best way to merge 2 or more dictionaries (Dictionary) in C#? (3.0 features like LINQ are fine).

I\'m thinking of a method signa

相关标签:
26条回答
  • 2020-11-22 09:12

    I know this is an old question, but since we now have LINQ you can do it in a single line like this

    Dictionary<T1,T2> merged;
    Dictionary<T1,T2> mergee;
    mergee.ToList().ForEach(kvp => merged.Add(kvp.Key, kvp.Value));
    

    or

    mergee.ToList().ForEach(kvp => merged.Append(kvp));
    
    0 讨论(0)
  • 2020-11-22 09:12

    or :

    public static IDictionary<TKey, TValue> Merge<TKey, TValue>( IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y)
        {
            return x
                .Except(x.Join(y, z => z.Key, z => z.Key, (a, b) => a))
                .Concat(y)
                .ToDictionary(z => z.Key, z => z.Value);
        }
    

    the result is a union where for duplicate entries "y" wins.

    0 讨论(0)
  • 2020-11-22 09:13

    Based on the answers above, but adding a Func-parameter to let the caller handle the duplicates:

    public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> dicts, 
                                                               Func<IGrouping<TKey, TValue>, TValue> resolveDuplicates)
    {
        if (resolveDuplicates == null)
            resolveDuplicates = new Func<IGrouping<TKey, TValue>, TValue>(group => group.First());
    
        return dicts.SelectMany<Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>>(dict => dict)
                    .ToLookup(pair => pair.Key, pair => pair.Value)
                    .ToDictionary(group => group.Key, group => resolveDuplicates(group));
    }
    
    0 讨论(0)
  • 2020-11-22 09:13

    Simplified from use compared with my earlier answer with a bool default of non-destructive merge if existing or overwrite entirely if true rather than using an enum. It still suits my own needs without any fancier code ever being required:

    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;
            });
        }
    }
    
    0 讨论(0)
  • 2020-11-22 09:13

    Note that if you use an extension method called 'Add', you get to use collection initializers to combine as many dictionaries as needed like this:

    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 讨论(0)
  • 2020-11-22 09:14

    Merging using an EqualityComparer that maps items for comparison to a different value/type. Here we will map from KeyValuePair (item type when enumerating a dictionary) to Key.

    public class MappedEqualityComparer<T,U> : EqualityComparer<T>
    {
        Func<T,U> _map;
    
        public MappedEqualityComparer(Func<T,U> map)
        {
            _map = map;
        }
    
        public override bool Equals(T x, T y)
        {
            return EqualityComparer<U>.Default.Equals(_map(x), _map(y));
        }
    
        public override int GetHashCode(T obj)
        {
            return _map(obj).GetHashCode();
        }
    }
    

    Usage:

    // if dictA and dictB are of type Dictionary<int,string>
    var dict = dictA.Concat(dictB)
                    .Distinct(new MappedEqualityComparer<KeyValuePair<int,string>,int>(item => item.Key))
                    .ToDictionary(item => item.Key, item=> item.Value);
    
    0 讨论(0)
提交回复
热议问题