C #에서 사전 병합 생각하고 있습니다. public static Dictionary<TKey,TValue>

Dictionary<T1,T2>C #에서 둘 이상의 사전 ( ) 을 병합하는 가장 좋은 방법은 무엇입니까 ? (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);

편집 : JaredPar와 Jon Skeet에서 멋진 솔루션을 얻었지만 중복 키를 처리하는 것을 생각하고있었습니다. 충돌의 경우 일관된 한 어떤 값이 dict에 저장되는지는 중요하지 않습니다.



답변

이것은 부분적으로 중복이 발생했을 때 어떤 일이 일어나고 싶은가에 달려 있습니다. 예를 들어 다음을 수행 할 수 있습니다.

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를 사용하고 사전이 키 / 값 쌍에 대한 반복을 지원한다는 것을 깨닫는 것입니다.


답변

나는 이렇게 할 것입니다 :

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

간단하고 쉽습니다. 이 블로그 게시물 에 따르면 기본 구현이 열거자가 아닌 인덱스로 요소에 액세스하므로 대부분의 루프보다 훨씬 빠릅니다 (이 답변 참조) .

중복이있는 경우 물론 예외가 발생하므로 병합하기 전에 확인해야합니다.


답변

여러 개의 키가있는 경우 ( “오른쪽”키가 “왼쪽”키를 대체 함), 여러 사전을 병합하고 (필요한 경우) 유형을 보존 할 수 있습니다 (유의 한 기본 공용 생성자가 필요하다는 제한 사항 포함).

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;
    }

}

답변

사소한 해결책은 다음과 같습니다.

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;
}

답변

다음을 시도하십시오

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);
}

답변

Dictionary<String, String> allTables = new Dictionary<String, String>();
allTables = tables1.Union(tables2).ToDictionary(pair => pair.Key, pair => pair.Value);

답변

나는 파티에 매우 늦었고 어쩌면 뭔가를 잃어 버렸지 만 중복 키가 없거나 OP가 말한 것처럼 “충돌의 경우 어떤 값이 dict에 저장되어 있는지는 중요하지 않습니다. 일관된 “”이 문제가 무엇입니까 (D2를 D1에 병합)?

foreach (KeyValuePair<string,int> item in D2)
            {
                 D1[item.Key] = item.Value;
            }

충분히 간단 해 보일 수도 있고 너무 간단 할 수도 있습니다. 이것은 중복 키가 없다는 것을 알고있는 일부 코드에서 사용중인 것입니다. 그래도 여전히 테스트 중이므로 나중에 찾는 것이 아니라 무언가를 간과하고 있는지 알고 싶습니다.