2009-12-13 4 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 списка «источник» и «целевых»

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 }; 

, что я хочу сделать список источников

  1. обновление только содержат sam и andy, так как bob и thomas не попадают в целевой список. Я сделал это

    источник = (от р в источник, где (с т в целевой выберите T) .Contains (р, новый PersonComparer()) выберите р) .ToList();

  2. В цель я должен «флаг» sam2, а andy - true, а по умолчанию jane помечен как «false», я не должен его менять.

Я попытался с помощью, но это снимает «Jane» от цели

//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 наконец тривиальный вопрос: как именно вы говорите «=>», когда вы разговариваете с коллегой кодера по телефону

ответ

2

Как Sander отметил, LINQ для запроса, не обновляется.

Однако, чтобы ответить на вопросы ... Ваш оригинальный запрос из

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

будет гораздо проще записать в виде:

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

Сказав, что вам нужно обновить PersonComparer в recursive упоминается.Это должно быть что-то вроде этого:

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

Для части 4 => можно прочитать как goes to.

+0

Nice ссылки. Спасибо – ram

+0

Не беспокойтесь. Я думаю, что это вопрос, который многие задаются вопросом, когда начинаете с LINQ. – RichardOD

1

Метод GetHashCode() должен использовать пройденный экземпляр obj, а не его собственный родитель.

+0

Хорошая точка, больше комментариев, чем ответ на вопрос. Точнее: когда .Equals (a, b) возвращает true, a.GetHashcode() должен равняться b.GetHashCode(). Кроме того, когда .Equals возвращает false, хэш-коды должны отличаться –

+0

ОК, так как бы вы написали этот метод GetHashCode? – ram

+0

err, вероятно, возвращает obj.GetHashCode(); – recursive

2

Linq не имеет актуальности для просмотра, потому что он работает от IEnumerable<T>. Вы можете создать новый перечислимый, основанный на исходном и целевом объектах, которые представляют нужную вам коллекцию.

Что-то, как это должно работать:

var combined = source.Where(x => target.Any(y => y == x)) 
Смежные вопросы