2013-07-12 1 views
0

LINQ를 사용하여 여러 개의 알 수없는 키로 작업 할 GroupJoin을 얻으려고합니다.LINQ 복합 키 GroupJoin이 컴파일 타임에 알려지지 않음

익명 형식의 솔루션을 보았지만 키는 항상 미리 정의되었습니다. 필자의 경우에는 사용자가 정의 했으므로 컴파일 할 때 정보를 알 수 없습니다. 키 값 목록과 키 값 배열을 사용하려고 시도했지만 일치하지 않습니다.

그래서 ...이 마법처럼 작동합니다

Func<Component, string> getKeyValue = x => x.Attributes       //from attributes 
              .Single(a => a.Name == _keyAttribute) //selects the key attribute 
              .Value;        //gets attribute value 

var leftJoin = source.GroupJoin(target,     //join 
           getKeyValue,   //on the same 
           getKeyValue,   //condition 
           (src, corresp) => new 
           { 
            src, 
            corresp 
           }) 
        .SelectMany(z => z.corresp.DefaultIfEmpty() 
               .Select(tgt => new { z.src, tgt })) //selects matching 
        .ToList();             //source and target 

을하지만이되지 않습니다 :

Func<Component, List<string>> getKeyValues = x => x.Attributes     //from attributes 
           .Where(a => _keyAttributes.Contains(a.Name)) //selects key attributes 
           .OrderBy(a => a.Name)      //order them by name 
           .Select(a => a.Value)      //gets attributes' values 
           .ToList(); 
var leftJoin = source.GroupJoin(target,     //join 
           getKeyValues,   //on the same 
           getKeyValues,   //condition 
           (src, corresp) => new 
           { 
            src, 
            corresp 
           }) 
        .SelectMany(z => z.corresp.DefaultIfEmpty() 
               .Select(tgt => new { z.src, tgt })) //selects matching 
        .ToList();             //source and target 

도움이된다면, 이것이 내가 일하고 있어요 구조입니다 :

List<string> _keyAttributes; 
List<Component> source; 
List<Component> target; 

[DataContract] 
public class Component 
{ 
    [DataMember] 
    public List<Attribute> Attributes { get; set; } 

    public Component() 
    { 
     new List<Attribute>(); 
    } 
} 

[DataContract] 
public class Attribute 
{ 
    [DataMember] 
    public string Name { get; set;} 
    [DataMember] 
    public string Value { get; set;} 
} 

LINQ 라이브러리를 사용하여이 문제를 해결할 방법이 있습니까? 아니면 내 자체 GroupJoin 확장 메서드가 필요합니까?

답변

0

당신이 제공하는 getKeyValues ​​선택자는 Component에서 List을 비교하여 비교할 수 없다는 것입니다. 각에서 반환 List 때문에 기본적으로이 일어나고있어, 참조에 의해 비교 될 것이다 : 그들은 참조를 기준으로 비교되기 때문에

var listA = new List<string> { "SomeString" }; 
var listB = new List<string> { "SomeString" }; 

bool areListsEqual = listA == listB; 

areListsEqual는 false를 돌려줍니다. 본질적으로 필요한 것은 EqualityComparer (GroupJoin의 오버로드를 통해 추가 할 수 있음)이거나 값이 인 속성을 비교하는 방법이 필요합니다.

Func<Component, string> getKeyValues = x => 
    string.Join(",", x.Attributes 
         .Where(a => _keyAttributes.Contains(a.Name)) 
         .OrderBy(a => a.Name) 
         .Select(a => a.Value).ToArray()); 

이 각 목록의 값을 나타내는 문자열을 생성합니다, 그것은 사용됩니다

(그러나 반드시 그것을 할 수있는 좋은 방법) 일하는 것이 뭔가의 예는 것 비교하려고. 더 좋은 방법은 포함 된 값을 기반으로 목록을 실제로 동일하게 만드는 것에 대한 논리를 가진 EqualityComparer을 사용하는 것입니다. 두 목록을 비교하는 방법은 here을 참조하십시오.

+0

값을 결합하지 않았습니다. 그들은 모두 문자열이기 때문에 작동합니다. 나는 반드시 그것을하는 좋은 방법은 아니지만 나는 그것이 할 것이라고 생각합니다. 쉼표가 아닌 고유 한 문자 조합이 있습니다. 감사합니다. –

+0

더 좋은 점은, List 또는 T []에 대한 EqualityComparer를 구현하여 GroupJoin의 추가 인수로 전달하는 솔루션을 계속 사용하겠습니다. –

+0

IEqualityComparer가 방법이었습니다! 고맙습니다! –

관련 문제