2010-06-01 4 views
3

는 다음과 같은 예를 생각해가 출력으로 "테스트", "t"를 생산하는 I 희망 것Linq Union의 문제는 무엇입니까?

public IEnumerable<String> Test() 
    { 
     IEnumerable<String> lexicalStrings = new List<String> { "test", "t" }; 
     IEnumerable<String> allLexicals = new List<String> { "test", "Test", "T", "t" }; 

     IEnumerable<String> lexicals = new List<String>(); 
     foreach (String s in lexicalStrings) 
      lexicals = lexicals.Union (allLexicals.Where (lexical => lexical == s)); 

     return lexicals; 
    } 

을하지만, (출력은 "t"입니다)하지 않습니다. 확실하지는 않지만 지연 처리를해야 할 수도 있습니다. 어떤 아이디어를 어떻게 작동 시키거나 좋은 대안으로 삼을 수 있습니까?

편집 : 이것은 단순한 예입니다. lexicalStringsallLexicals은 원본 코드에서 다른 유형입니다. 그래서 저는 이것을 직접 결합 할 수는 없습니다.

Edit2가 더 같은 외모를 해결하는 문제 :

public IEnumerable<Lexical> Test() 
    { 
     IEnumerable<String> lexicalStrings = new List<String> { "test", "t" }; 
     IEnumerable<Lexical> allLexicals = new List<Lexical> { ... }; 

     IEnumerable<Lexical> lexicals = new List<Lexical>(); 
     foreach (String s in lexicalStrings) 
      lexicals = lexicals.Union (allLexicals.Where (lexical => lexical.Text == s)); 

     return lexicals; 
    } 

답변

3

. 그래도 여전히 잘 보이는데도 코드가 올바르게 작동하지 않는 것이 흥미 롭습니다.

 IEnumerable<String> lexicalStrings = new List<String> { "test", "t" }; 
     IEnumerable<String> allLexicals = new List<String> { "test", "Test", "T", "t" }; 

     IEnumerable<String> lexicals = new List<String>(); 
     foreach (String s in lexicalStrings) 
     { 
      lexicals = lexicals.Union(
       allLexicals.Where(
       lexical => 
       { 
        Console.WriteLine(s); 
        return lexical == s; 
       } 
       ) 
      ); 
     } 
     Console.WriteLine(); 
     foreach (var item in lexicals) 
     { 
     } 

당신이 어떤 결과를 기대 :

의 앱을 조금 수정할 수? 여기있다 :

t 
t 
t 
t 
t 
t 
t 
t 

재미 있지 않습니까?

IEnumerable<String> lexicalStrings = new List<String> { "test", "t" }; 
    IEnumerable<String> allLexicals = new List<String> { "test", "Test", "T", "t" }; 

    IEnumerable<String> lexicals = new List<String>(); 
    foreach (String s in lexicalStrings) 
    { 
     string ls = s; 
     lexicals = lexicals.Union(
      allLexicals.Where(
      lexical => 
      { 
       Console.WriteLine(ls); 
       return lexical == ls; 
      } 
      ) 
     ); 
    }    
    foreach (var item in lexicals) 
    {     
    } 

이제 출력 결과는 괜찮 :

이제 다시 수정할 수

test 
test 
test 
test 
t 
t 
t 
t 

왜 발생합니까? 클로저 - 내부 람다에서 바깥 쪽 var를 사용합니다. 실제로 시퀀스를 반복하지 않기 때문에 s의 현재 값은 람다에 들어 가지 않습니다. foreach 출구와 s의 모든 내부 복사본은 마지막 반복의 값을 유지합니다. 내부 변수의 경우 반복 할 때마다 만들어지는 값 사본을 보유합니다. 이 충돌은 LINQ 내부의 게으름에서 비롯됩니다. List.AddRange 같은 루프를 수행하면 결과가 괜찮습니다. 왜냐하면 List.AddRange 반복 반복 때문입니다.

+0

설명과 쉬운 고마워! 위로 대답했다. – Foxfire

+0

AddRange를 사용하려고 생각했지만 목록에서 중복이 발생합니다 (어떤 Union이 자동으로 피해야하는지). – Foxfire

+0

@Foxfire 당신은 실제로 intersect를 사용해야합니다. 문제를 해결합니다. – Andrey

0

이 당신이 달성하려고하는 무엇인가?

lexicals.Union(allLexicals).Distinct(StringComparer.OrdinalIgnoreCase) 

편집 :

lexicals.Intersect(allLexicals, StringComparer.OrdinalIgnoreCase)

편집 2 : 더 나은 아직 @ 데이브가 제안

또는 서로 다른 유형의 경우

그 중 하나가 구현해야 IEqualityComparer 다른쪽에. 그런 다음 교차 방법이 클래스를 통과 : 당신은 다른 대답 설명으로 잘못된 연산을 사용하는

lexicals.Intersect(allLexicals, new MyCustomTComparer())

+0

lexicalStrings 및 allLexicals가 원래 코드에서 다른 유형이기 때문에 질문에 더 많은 설명을 추가했습니다. – Foxfire

+0

괜찮은 코드가 제대로 작동하지 않는 이유에 대한 질문이 더 많으므로이 부분에 대한 설명이 필요합니다.문제는 클로저입니다. – Andrey

1
public IEnumerable<Lexical> Test() 
{ 
    var lexicalStrings = new List<String> { "test", "t" }; 
    var allLexicals = new List<Lexical> { ... }; 

    var lexicals = new List<Lexical>(); 
    foreach (string s in lexicalStrings) 
    { 
     lexicals.AddRange(allLexicals.Where (lexical => lexical.Text == s)); 
    } 

    return lexicals; 
} 
+0

lexicalStrings와 allLexicals가 원래 코드에서 다른 유형이기 때문에 질문에 더 많은 설명을 추가했습니다. – Foxfire

+0

그들은 몇 가지 일반적인 기본 유형을 공유해야하며, 그렇지 않으면 캐스팅/변환하여 결과로 결합해야합니다. 두 가지 완전히 다른 유형의 IEnumerable 을 사용할 수 없습니다. IEqualityComparer 을 전달할 수 있으므로 같음 비교 (즉, 예에서 lexical == s)를 작성하십시오. –

+0

저는 그것들을 결합하고 싶지 않습니다. 나는 여러 linq "where"절의 결과의 결합을 원한다. (gerenal에서 작동하는 아래 예제를 보자. 예상 출력을 제공하지 않는다.) – Foxfire