2012-08-15 2 views
2

나는 (대부분의 경우) 몇 가지 값만 다른 여러 동적 개체가 있습니다. 이러한 개체를 하나의 단일 개체로 병합 할 수 있기를 원합니다. 충돌이 발생한 경우 (두 값이 같지 않은 경우) 컬렉션 또는 다른 동적 개체에 저장하는 것이 좋습니다.C에서 # 두 개의 유사한 동적 개체를 병합하여 컬렉션을 만드는 중

나는 expandoObject 클래스를 사용하여 내 객체를 dictionairy로 캐스팅하고 병합 할 수 있지만 충돌이있는 콜렉션을 만드는 병합 병합에 대한 기사 나 소스를 찾지 못했습니다.

쉽게 구현하고 효율적인 방식으로이를 수행 할 수있는 방법이 있습니까?

난 당신에게 내가

//returns a dynamic object from JSON (output from DataBase) 
JsonReader reader = new JsonReader(); 
dynamic object = reader.Read(input); 

//Creates a dictionairy with all the fieldnames and values. 
IDictionary<string, dynamic> properties = (IDictionary<string, dynamic>)object; 

//My goal is to merge multiple of these objects into one single object and 
//creating collections when values are different from each other. 
+0

시도한 것을 설명하기위한 코드를 보여줄 수 있습니까? – psubsee2003

+0

물론, 일부 코드를 표시하려면 내 게시물을 편집하겠습니다 –

답변

3

문제를 달성하기 위해 노력하고있어 작은 아이디어를 제공하는 몇 가지 코드 샘플을 게시합니다하면 IDictionary <> 인터페이스를 기반으로 할 것으로 보인다. 각 키에 대해 하나의 값만 있다고 가정합니다. 필자는 키 값 수집 목록을 나타내는 LINQ-ish IEnumerable<IGrouping<TKey,TValue>>으로 이동하기를 원합니다.

LINQ는 .GroupBy 또는 .ToLookup 호출을 할 때 이러한 개체를 내 보냅니다.

using System.Linq; 

Dictionary<string, dynamic> A = ...; 
Dictionary<string, dynamic> B = ...; 

// naiive atempt: 
var lookup = 
    A.Keys.Concat(B.Keys) 
     .ToDictionary(key => key, key => new dynamic[]{ A[key], B[key] })); 

은 물론이 작동하지 않습니다,하지만 난 그게 노출 것입니다 무슨 문제보고를 서면으로 작성했습니다 :
은의 다음 놀자. 첫째 - 당신은 아마도 Concat'ing 때 중복 키를 얻을 것입니다. 그런 다음 모든 키가 A와 B에있는 것은 아니므로 색인 작성자가 던집니다. 다음으로, 나는 원래의 객체가 string-to-one-value 였다고 가정하고, 이미 충돌 한 객체에 대해 작업 할 것입니다. 그런 다음 여러 A/B 개체를 사용하는 반면, 여러 작업을 수행 할 수는 있습니다.

IEnumerable<Dictionary<string, dynamic>> inputs = ....; 

// btw. GropuBy returns a lookup, too :) a key -> all matches 
var matched_by_keys = inputs.GroupBy(pair => pair.Key); 

var final = matched_by_keys.ToDictionary(group => group.Key, group => group); 

거기를보십시오. 나는 모든 사전을 가져 왔고 그들의 열쇠에 따라 "그냥 짝을 지었다". 결과적으로 각 기존 키를 이전에 해당 키에 할당 된 일련의 값에 바인딩하는 조회가 있습니다. 그 결과 matched_by_keys은 사전이 아닌 Enumerable이므로 나중에 변환됩니다. ToDictionary에 대한 매개 변수를 살펴보십시오. Group 자체는 IEnumerable이며, 키는 지적되어야하며 그룹은 변경되지 않았습니다.

여전히 입력은 단일 값인 IDictionary에서만 작동합니다. 당신이 너무 다중 값 입력과 같은 일을 할 필요가있는 경우에, 당신은 쉽게 조회에 IDictionaries을 transalte 그들에 대한 작업을 수행 할 수 있습니다

IEnumerable<Dictionary<string, dynamic>> inputs1 = ....; // normal items 
IEnumerable<ILookup<string, dynamic>> inputs2 = ....; // items that previously already collided 

var allAsLookups = 
    inputs1.ToLookup(pair => pair.Key, pair => pair.Value) 
    .Concat(inputs2); 

// btw. GropuBy returns a lookup, too :) a key -> all matches 
var matched_by_keys = lookups.GroupBy(lk => lk.Key); 

var final1 = matched_by_keys.ToDictionary(group => group.Key, group => group.SelectMany(s=>s)); 

주를 마지막 그룹은 지금 번역했다 방법에 대해 설명합니다. 이 예에서 그룹은 IEnumerable<Value>이 아니지만 IEnumerable<IEnumerable<Value>>인데 입력이 인 경우은 1 값만 있더라도 여러 값을 가질 수 있기 때문입니다. 그래서, thit은 평평 해져야했고, 이것은 SelectMany에 의해 이루어졌습니다. 그것은 항목이 이미 IEnumerable 이었기 때문에 아무것도 계획 할 필요가 없었기 때문에 s => s이면 충분했습니다.

GroupBy, ToLookup 및 ToDictionary의 서로 다른 오버로드를 사용하면 많은 유용한 효과를 얻을 수 있습니다. 과부하로 게임하십시오!

+0

매우 유용한 정보와 잘 설명! 나는이 경우에는 작동하지 않는 버전에 대해 어떻게 생각 하는지를 좋아합니다. 정보를 제공해 주셔서 감사합니다. 저는 여기서부터 뭔가를 할 수 있다고 확신합니다! :) –

1

값이 dynamic이기 때문에 실제로 볼 수 있듯이 값이나 컬렉션을 저장할 수 있습니다.

사전의 모음이 필요합니다.이 경우 배열입니다.

var props1 = new Dictionary<string, dynamic> 
    { 
     {"uniq1", "uniq1"}, 
     {"same", "same1"}, 
    }; 
var props2 = new Dictionary<string, dynamic> 
    { 
     {"uniq2", "uniq2"}, 
     {"same", "same2"}, 
    }; 
var props3 = new Dictionary<string, dynamic> 
    { 
     {"uniq3", "uniq3"}, 
     {"same", "same3"}, 
    }; 

var props = new[] { props1, props2, props3 }; 

그런 다음 첫 번째를 얻고 다음에 그 병합합니다. 키가 이미있는 경우 이미 목록인지 또는 키를 작성해야하는지 확인하십시오. 키가 존재하지 않으면 단순히 추가하십시오. 동적 오브젝트가 Expando 경우

merged 
Count = 4 
    [0]: {[uniq1, uniq1]} 
    [1]: {[same, System.Collections.Generic.List`1[System.Object]]} 
    [2]: {[uniq2, uniq2]} 
    [3]: {[uniq3, uniq3]} 
merged["same"] 
{System.Collections.Generic.List<object>} 
    [0]: "same1" 
    [1]: "same2" 
    [2]: "same3" 
+0

대단히 감사합니다!. 훌륭하게 완벽한 예제로 설명했습니다. 나는 이것을 시도하고 깨끗한 코드를 이해하고 이해하기 쉽도록 :). –

1

, 당신은 다음과 같이 Linq를 사용할 수 있습니다 :

var objectList = new List<dynamic>() {...}; 

var result = objectList.SelectMany(obj => 
          (IDictionary<string, dynamic>)obj.ToList()) 
      .GroupBy(pair => pair.Key) 
      .ToDictionary(group => group.Key, 
          group => group.Select(pair => pair.Value)); 

먼저, 모든 KeyValuePair<string, dynamic>에서 선택 SelectMany를 사용

var merged = props.First(); 

foreach (var prop in props.Skip(1)) 
{ 
    foreach (var key in prop.Keys) 
    { 
     dynamic oldValue; 
     if (merged.TryGetValue(key, out oldValue)) 
     { 
      if (oldValue is IList<dynamic>) 
       merged[key].Add(prop[key]); 
      else 
       merged[key] = new List<dynamic> { oldValue, prop[key] }; 
     } 
     else 
      merged.Add(key, prop[key]); 
    } 
} 

merged로 설정됩니다 동적 객체,이 방법은 같은 키를 가진 목록을 받아 들일 것입니다.

그런 다음 키로 그룹화하고 기능 ToDictionary을 사용하여 결과를 얻으십시오.

+0

나는 SelectMany 함수의 사용을 좋아한다. 고마워! :) –

+0

'obj.ToList()가 필요합니까? –

관련 문제