제목은 충분히 기본적입니다. 내가 할 수없는 이유 :
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());
답변
원래 질문에 대한 의견은 이것을 아주 잘 요약합니다.
아무도 그 기능을 설계, 지정, 구현, 테스트, 문서화 및 제공하지 않았기 때문입니다. -@Gabe Moothart
그 이유는? 글쎄요, 딕셔너리 병합의 동작이 프레임 워크 지침에 맞는 방식으로 추론 될 수 없기 때문일 것입니다.
AddRange
데이터 범위가 중복 항목을 허용하므로 범위가 연관 컨테이너에 의미가 없기 때문에 존재하지 않습니다. 예를 들어 IEnumerable<KeyValuePair<K,T>>
해당 컬렉션 이있는 경우 중복 항목을 방지하지 않습니다.
키-값 쌍 모음을 추가하거나 두 사전을 병합하는 동작은 간단합니다. 그러나 여러 중복 항목을 처리하는 방법은 그렇지 않습니다.
중복을 처리 할 때 메서드의 동작은 어떻게됩니까?
내가 생각할 수있는 적어도 세 가지 해결책이 있습니다.
- 중복 된 첫 번째 항목에 대해 예외를 발생시킵니다.
- 모든 중복 항목을 포함하는 예외 발생
- 중복 무시
예외가 발생하면 원본 사전의 상태는 어떻습니까?
Add
거의 항상 원자 적 작업으로 구현됩니다. 성공하고 컬렉션의 상태를 업데이트하거나 실패하고 컬렉션의 상태는 변경되지 않은 상태로 유지됩니다. 으로 AddRange
복제 오류로 인해 실패 할 수 있습니다, 방법은 일관성있는 동작을 유지 Add
또한 중복에 예외를 throw하여 원자 확인하고 변경으로 원래 사전의 상태를두고하는 것입니다.
API 소비자로서 중복 요소를 반복적으로 제거해야하는 것은 지루할 것입니다. 이는 모든 중복 값 AddRange
을 포함하는 단일 예외를 throw해야 함을 의미 합니다.
선택은 다음과 같이 요약됩니다.
- 모든 중복 항목과 함께 예외를 throw하고 원본 사전은 그대로 둡니다.
- 중복을 무시하고 계속하십시오.
두 가지 사용 사례를 모두 지원하는 주장이 있습니다. 이를 위해 IgnoreDuplicates
서명에 플래그를 추가 합니까?
IgnoreDuplicates
(true로 설정) 플래그는 기본이되는 구현으로, 상당한 속도를 제공 할 것 중복 검사에 대한 코드 우회.
이제 AddRange
두 경우를 모두 지원할 수 있지만 문서화되지 않은 부작용 이있는 플래그가 있습니다 (프레임 워크 디자이너가 피하기 위해 정말 열심히 노력한 것입니다).
요약
중복을 처리 할 때 명확하고 일관 적이며 예상되는 동작이 없기 때문에 모두 함께 처리하지 않고 시작할 방법을 제공하지 않는 것이 더 쉽습니다.
계속해서 사전을 병합해야하는 경우, 물론 응용 프로그램에 적합한 방식으로 작동하는 사전을 병합하는 자체 확장 메서드를 작성할 수 있습니다.
답변
몇 가지 해결책이 있습니다.
Dictionary<string, string> mainDic = new Dictionary<string, string>() {
{ "Key1", "Value1" },
{ "Key2", "Value2.1" },
};
Dictionary<string, string> additionalDic= new Dictionary<string, string>() {
{ "Key2", "Value2.2" },
{ "Key3", "Value3" },
};
mainDic.AddRangeOverride(additionalDic); // Overrides all existing keys
// or
mainDic.AddRangeNewOnly(additionalDic); // Adds new keys only
// or
mainDic.AddRange(additionalDic); // Throws an error if keys already exist
// or
if (!mainDic.ContainsKeys(additionalDic.Keys)) // Checks if keys don't exist
{
mainDic.AddRange(additionalDic);
}
…
namespace MyProject.Helper
{
public static class CollectionHelper
{
public static void AddRangeOverride<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
{
dicToAdd.ForEach(x => dic[x.Key] = x.Value);
}
public static void AddRangeNewOnly<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
{
dicToAdd.ForEach(x => { if (!dic.ContainsKey(x.Key)) dic.Add(x.Key, x.Value); });
}
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
{
dicToAdd.ForEach(x => dic.Add(x.Key, x.Value));
}
public static bool ContainsKeys<TKey, TValue>(this IDictionary<TKey, TValue> dic, IEnumerable<TKey> keys)
{
bool result = false;
keys.ForEachOrBreak((x) => { result = dic.ContainsKey(x); return result; });
return result;
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
action(item);
}
public static void ForEachOrBreak<T>(this IEnumerable<T> source, Func<T, bool> func)
{
foreach (var item in source)
{
bool result = func(item);
if (result) break;
}
}
}
}
즐기세요.
답변
누군가가 나처럼이 질문을 접하게되면 IEnumerable 확장 메서드를 사용하여 “AddRange”를 달성 할 수 있습니다.
var combined =
dict1.Union(dict2)
.GroupBy(kvp => kvp.Key)
.Select(grp => grp.First())
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
사전을 결합 할 때 주요 트릭은 중복 키를 처리하는 것입니다. 위의 코드에서는 부분 .Select(grp => grp.First())
입니다. 이 경우 단순히 중복 그룹에서 첫 번째 요소를 가져 오지만 필요한 경우 더 정교한 논리를 구현할 수 있습니다.
답변
내 생각 엔 무슨 일이 일어 났는지에 대해 사용자에게 적절한 출력이 부족한 것 같습니다. 사전에 반복 키를 가질 수 없기 때문에 일부 키가 교차하는 두 사전 병합을 어떻게 처리할까요? 물론 “I do n’t care”라고 말할 수 있지만 이는 false를 반환하거나 반복되는 키에 대한 예외를 던지는 규칙을 위반하는 것입니다.
답변
당신은 이것을 할 수 있습니다
Dictionary<string, string> dic = new Dictionary<string, string>();
// dictionary other items already added.
MethodThatReturnAnotherDic(dic);
public void MethodThatReturnAnotherDic(Dictionary<string, string> dic)
{
dic.Add(.., ..);
}
또는 addrange 및 / 또는 위의 패턴을 사용하는 목록을 사용합니다.
List<KeyValuePair<string, string>>
답변
새 딕셔너리를 처리하는 경우 (그리고 잃을 기존 행이없는 경우) 항상 다른 객체 목록에서 ToDictionary ()를 사용할 수 있습니다.
따라서 귀하의 경우 다음과 같이 할 수 있습니다.
Dictionary<string, string> dic = new Dictionary<string, string>();
dic = SomeList.ToDictionary(x => x.Attribute1, x => x.Attribute2);
답변
중복 키가 없을 것임을 알고 있다면 다음을 수행 할 수 있습니다.
dic = dic.Union(MethodThatReturnAnotherDic()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
중복 키 / 값 쌍이있는 경우 예외가 발생합니다.
왜 이것이 프레임 워크에 없는지 모르겠습니다. 해야한다. 불확실성은 없습니다. 예외를 던지십시오. 이 코드의 경우 예외가 발생합니다.