2009-12-13 6 views
0

아마이 질문은 이전에 이미 물어 보았지만 내 Google-fu와 SO-Search는 내가 원하는 것을 얻을 수 없었습니다.LINQ- 값 비교 및 ​​업데이트

나는 사용자 정의 클래스와 IEqualityComparer로 구현 된 (클래스의 동등성을 검사하기위한) 커스텀 클래스 비교자를 가지고있다.

public class Person 
{ 
     public string Name { get; set; } 
     public bool Flag { get; set; } 
} 

public class PersonComparer : IEqualityComparer<Person> 
{ 
     #region IEqualityComparer<Person> Members 

     public bool Equals(Person x, Person y) 
     { 
      //case insensitive compare 
      return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase); 
     } 

     public int GetHashCode(Person obj) 
     { 
      return base.GetHashCode(); 
     } 

     #endregion 
} 

하고 코드의 주요 부분에 나는 2에는 "소스"와 "대상"난 단지에

  1. 업데이트 소스 목록을 수행 할 작업을

    Person bob = new Person() { Name = "Bob" }; 
    Person sam = new Person() { Name = "Sam" }; 
    Person andy = new Person() { Name = "Andy" }; 
    Person thomas = new Person() { Name = "Thomas" }; 
    Person jimmy = new Person() { Name = "Jimmy" }; 
    Person sam2 = new Person() { Name = "sam" }; // note the lower case 
    Person jane = new Person() { Name = "Jane" }; 
    List<Person> source = new List<Person>() { bob, sam, andy, thomas }; 
    List<Person> target = new List<Person>() { sam2, andy,jane }; 
    

    이 bob과 thomas가 목표 목록에 없기 때문에 sam과 andy를 포함합니다. 나는 이것을했다

    소스 = (소스에서 p에서 대상 선택 t에서) .Contains (p, 새 PersonComparer()) 선택 p) .ToList();

  2. 대상에서 sam2 및 andy를 true로 설정해야하며 jane은 기본적으로 "false"로 플래그가 지정되어 있으므로 변경하지 않아야합니다.

나는 이것을 사용하여 시도하지만,이 대상에서 "제인"을 제거

//sets sam2 & andy to true, removes Jane 
target = (from p in target.Select(t => { t.Flag = true; return t; }) 
      where (from s in source 
      select s).Intersect(select p).ToList(); 

는 LINQ 전문가 내가 뭘 잘못 말해 줄래?

3. 쿼리 1을 작성하는 더 좋은 방법은 있습니까?

4.And 마지막으로 사소한 질문 : 당신이 제 4의 전화

답변

2

, LINQ는하지 쿼리 업데이트입니다.

source = source.Intersect(target, new PersonComparer()).ToList(); 

당신이 recursive로 PersonComparer을 업데이트해야했다 가졌 : 그러나

이 질문에 대답하기 위해 ...

source = (from p in source where (from t in target select t) 
    .Contains(p, new PersonComparer()) select p).ToList(); 

의 원래 쿼리는 훨씬 더 간단하게 작성 될 것 말하는.그 결과는 아래와 같습니다 :

public int GetHashCode(Person obj) 
{ 
    return obj == null ? 0 
     : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name); 
} 

내가 정말 특히 두 번째 쿼리를 이해하지 못하는 두려워 ...하지만 기존 오브젝트를 변경하려는 경우, 내가 대신 foreach 루프를 건의 할 것 LINQ를 사용하려고했습니다. 부작용이있는 검색어는 일반적으로 좋지 않습니다.

당신 이 비슷한 평균 뭔가 :

// You may want to make some singleton instance available, as this has no state 
PersonComparer comparer = new PersonComparer(); 
foreach (Person person in target) 
{ 
    if (source.Contains(person, comparer)) 
    { 
     person.Flag = true; 
    } 
} 
+0

>> 부작용이있는 검색어는 일반적으로 좋지 않습니다. 알았습니다. 감사. – ram

1

통해 동료 코더에 이야기 할 때이 말을 어떻게 정확하게 "는 =>"=>goes to로 읽을 수 있습니다.

+0

멋진 링크. 감사합니다 – ram

+0

걱정하지 마십시오. 많은 사람들이 LINQ를 시작할 때 궁금해하는 질문입니다. – RichardOD

1

메서드는 obj 전달 된 인스턴스가 아니라 자신의 부모를 사용해야합니다.

+0

좋은 지적이지만 질문에 대한 답변보다 많은 코멘트. 좀 더 정확히 말하면 : .Equals (a, b)가 true를 반환하면 a.GetHashcode()는 b.GetHashCode()와 같아야합니다. 또한 .Equals가 false를 반환하면 해시 코드가 달라야합니다. –

+0

이 GetHashCode 메서드를 작성하는 방법은 무엇입니까? – ram

+0

오류가 발생했습니다. 아마도 obj.GetHashCode()를 반환합니다. – recursive

2

Linq는 IEnumerable<T>에서 작동하므로 목록을 업데이트하지 않습니다. 필요한 컬렉션을 나타내는 소스 및 대상을 기반으로 새 열거 형을 만들 수 있습니다. 이 같은

뭔가 작동합니다 : 샌더가 지적했듯이

var combined = source.Where(x => target.Any(y => y == x))