2011-11-08 6 views
2

들어오는 값 시퀀스를 요약하는 Linq를 사용하여 함수를 만들고 싶습니다. 이 기능은 다음과 비슷한 모습이 될 것Linq : 빈 IGrouping 만들기

IDictionary<TKey, Summary<TKey>> Summarize<TKey, TValue>(IEnumerable<TValue> values) 
{ 
    return values 
     .ToLookup(val => GetKey(val))   // group values by key 
     .Union(*an empty grouping*)   // make sure there is a default group 
     .ToDictionary(
      group => group.Key, 
      group => CreateSummary(group)); // summarize each group 
} 

캐치는 결과 IDictionary이 들어오는 순서가 키에 값을 포함하지 않는 경우에도 기본 (TKEY)에 대한 항목이 있어야한다는 것입니다. 순전히 기능적인 방식으로이 작업을 수행 할 수 있습니까? (변경 가능한 데이터 구조를 사용하지 않습니다.)

내가 할 수있는 유일한 방법은 .Union을 사전에 파이프하기 전에 호출하여 호출하는 것입니다. 그러나 그것은 저에게 명시적인 클래스 없이는 가능하지 않은 빈 IGrouping을 생성해야합니다. 이것을 할 수있는 우아한 방법이 있습니까?

편집 : TKey는 값 유형이라고 가정 할 수 있습니다.

답변

3

을하는 데 도움이

IDictionary<TKey, Summary<TKey>> Summarize<TKey, TValue>(IEnumerable<TValue> values) 
{ 
    return values 
     .ToLookup(val => GetKey(val))   // group values by key 
     .Union(Enumerable.Repeat(default(TKey), 1).ToLookup(x => GetKey(x))) 
     .ToDictionary( 
      group => group.Key, 
      group => CreateSummary(group)); // summarize each group 
} 

희망 : 당신은 조합과 솔루션을 원하는 경우처럼

IDictionary<TKey, Summary<TKey>> Summarize<TKey, TValue>(IEnumerable<TValue> values) 
{ 
    return values 
     .ToLookup(val => GetKey(val))   // group values by key 
     .Select(x => x.Any() ? x : Enumerable.Repeat(default(TKey), 1).ToLookup(x => GetKey(x))) 
     .ToDictionary( 
      group => group.Key, 
      group => CreateSummary(group)); // summarize each group 
} 

, 당신은 기본 조회 테이블을 만들 같은 논리를 사용할 수 있습니다 GroupBy 또는 ToLookup에서 비어있는 그룹을 가져올 수 없습니다. 아마도 의도적 인 이유가있을 것입니다.

순전히 기능적 방식으로 수행 할 수 있습니까? (변경 가능한 데이터 구조를 사용하지 마십시오.)

이러한 학문적 요구 사항은 재미있을 수 있지만 모든 솔루션은 간단하고 간단한 구현과 비교되어야합니다. 당신이 빈 그룹을 원하는 경우

Dictionary<TKey, Summary<TKey>> result = values 
    .GroupBy(val => GetKey(val)) 
    .ToDictionary(g => g.Key, g => CreateSummary(g)); 

TKey x = default(TKey); 
if (!result.ContainsKey(x)) 
{ 
    result[x] = CreateSummary(Enumerable.Empty<TValue>()); 
} 

return result; 

지금, 단지 그것을 위해 클래스를 추가 할 수 있습니다

public class EmptyGroup<TKey, TValue> : IGrouping<TKey, TValue> 
{ 
    public TKey Key {get;set;} 

    public IEnumerator GetEnumerator() 
    { 
    return GetEnumerator<TValue>(); 
    } 
    public IEnumerator<TValue> GetEnumerator<TValue>() 
    { 
    return Enumerable.Empty<TValue>().GetEnumerator<TValue>(); 
    } 
} 

은 다음과 같이 사용합니다 :

EmptyGroup<TKey, TValue> empty = new EmptyGroup<TKey, TValue>(Key = default<TKey>()); 
0

조회 테이블을 확인하는 항목이 있으면 추가 할 수 있으며, 그렇지 않은 경우 새 조회 테이블을 만들 수 있습니다. 이것은 다른 값이있는 경우 기본값을 추가하지 않는다는 점에서 제안 된 노동 조합 솔루션과 다릅니다.

볼 :이

1

허용 대답은 무엇입니까 내가 찾고 있었지만 그것은 나를 위해 작동하지 않았다. 어쩌면 나는 뭔가를 놓쳤지 만 컴파일되지 않았다. 해결하기 위해 코드를 수정해야했습니다. 감사

public class EmptyGroup<TKey, TValue> : IGrouping<TKey, TValue> 
{ 
    public TKey Key { get; set; } 

    public IEnumerator<TValue> GetEnumerator() 
    { 
     return Enumerable.Empty<TValue>().GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

완벽하게이

var emptyGroup = new EmptyGroup<Customer, AccountingPaymentClient>(); 
+0

작품처럼 사용할 : 여기에 나를 위해 일한 코드입니다 D – Nate