2015-02-28 2 views
4

Я пытаюсь изучить выражения Linq/Lambda и застрял где-то.Как использовать linq `Except` с несколькими свойствами с другим классом?

Что я делал

я создал два класса со свойствами, которые имеют некоторые общие свойства в них. Классы похожи (это тестовый код).

class TestA 
    { 
     public int Id { get; set; } 
     public int ProductID { get; set; } 
     public string Category { get; set; } 

     public TestA(int id, int procid, string category) 
     { 
      this.Id = id; 
      this.ProductID = procid; 
      this.Category = category; 
     } 
    } 

    class TestB 
    { 
     public int ProductID { get; set; } 
     public string Category { get; set; } 

     public TestB(int procid, string category) 
     { 
      this.ProductID = procid; 
      this.Category = category; 
     } 
    } 

Затем я создал два списка для них,

 List<TestA> testListA = new List<TestA>(); 
     List<TestB> testListB = new List<TestB>(); 
     TestA t1 = new TestA(1, 254, "ProductA"); 
     TestA t2 = new TestA(1, 236, "ProductA"); 
     TestA t3 = new TestA(1, 215, "ProductB"); 
     TestA t4 = new TestA(1, 175, "ProductB"); 
     TestA t5 = new TestA(1, 175, "ProductC"); 
     testListA.Add(t1); 
     testListA.Add(t2); 
     testListA.Add(t3); 
     testListA.Add(t4); 
     testListA.Add(t5); 

     TestB tt1 = new TestB(254, "ProdcutA"); 
     TestB tt2 = new TestB(215, "ProductB"); 
     TestB tt3 = new TestB(175, "ProductC"); 
     testListB.Add(tt3); 
     testListB.Add(tt2); 
     testListB.Add(tt1); 

Теперь для результата я хотел t2, как это ProductID матч не в testListB И t4 как это соответствие ProductID в testListB но не имеют того же Category.
1) Я не нужна List<A> каждой записи которых: больше не имеет ProductID провел в testListB

, которые я могу получить, как,

testListA.Select(x => x.ProductID).Except(testListB.Select(x => x.ProductID)); 

2) больше не имеет запись, которая имеет соответствие ProductID и Category в testListB

, которые я могу получить с помощью,

testListA.Where(a => testListB.Any(b => a.ProductID == b.ProductID && a.Category != b.Category)); 

** Мой вопрос **
Возможно ли сделать два выражения linq для получения результата. Я думал об использовании средства IEqualityComparer, но я не уверен, как реализовать его для двух разных типов классов. Таким образом, либо объединение вышеуказанного запроса в один запрос, либо каким-либо другим способом встраивать пользовательский Comparer для двух разных типов классов. Или есть другой простой способ?

+0

Я не вижу никаких доказательств в вашем коде, используя GetHashCode. Я знаю, что это деликатный вопрос сам, но если вы хотите, чтобы мы помогли вам, вы должны, по крайней мере, представить код, который SUPPOSED использовать GetHashCode. – S22

+0

Как я уже сказал, в настоящее время я использую два отдельных запроса, чтобы получить результат. Я думал о реализации 'IEqualityComparer', но я не был уверен, как реализовать« GetHashCode », поэтому я не включил здесь. Как вы знаете, реализуете ли вы 'IEqualityComparer'. Затем вам нужно реализовать 'GetHashCode' – user2745246

+0

Извините, но при чтении большего количества бросков ваш пост был наиболее информативным, поэтому мои извинения. Я понимаю, что вы хотите реализовать IEqualityComparer. – S22

ответ

6

Вы сказали, что вам нужно только эти объекты testListA:

  • есть не соответствие ProductID в testListB
  • есть существующие mathing ProductID, но с разными Category

Итак, ваш фильтр должен быть:

!testListB.Any(b => a.ProductID == b.ProductID && a.Category == b.Category)

Таким образом, изменить код, как:

testListA.Where(a => !testListB.Any(b => a.ProductID == b.ProductID && a.Category == b.Category)); 

Второй подход:

Или вы можете создать новый List<TestA> из второго списка:

var secondListA = testListB.Select(x=> new TestA(){Category=x.Category, ProductID=x.ProductID}).ToList(); 

А затем создать свой Comparer:

sealed class MyComparer : IEqualityComparer<TestA> 
{ 
    public bool Equals(TestA x, TestA y) 
    { 
     if (x == null) 
      return y == null; 
     else if (y == null) 
      return false; 
     else 
      return x.ProductID == y.ProductID && x.Category == y.Category; 
    } 

    public int GetHashCode(TestA obj) 
    { 
     return obj.ProductID.GetHashCode(); 
    } 
} 

И использовать Except() перегрузку, которая производит разность множеств, представленных двумя последовательностями, используя указанный IEqualityComparer<T> для сравнения значений .:

var result = testListA.Except(secondListA, new MyComparer()).ToList(); 
+0

Эй, спасибо за быстрый ответ. Теперь, когда я смотрю на выражение. Ifeel немой, не понимая, что использовать 'where' с' || 'спасибо. Но я просто удивляюсь, что можно реализовать 'IEqualityComparer' для двух разных типов классов. – user2745246

+0

@ user2745246 Нет, 'IEqualityComparer ' - это интерфейс для объекта, который выполняет сравнение на двух объектах типа 'T'. –

+0

Да, спасибо, я только начал читать об этом. Теперь я понял, как это работает.Я попробую свой путь и попытаюсь найти, есть ли другой способ получить его, поскольку я пытаюсь изучить linq. И я подожду 2 или 3 дня, чтобы получить больше ответов с разными апробатами, если не будет никаких новых азартных игр, тогда я приму это как ответ. Спасибо за ответ еще раз. – user2745246

-1

Прежде всего, вы можете переопределить функция Equals, поэтому вы можете легко сравнить 2 объекта по некоторым критериям. Вы также можете переопределить GetHashCode, вы не сможете его реализовать, поскольку он уже реализован System.Object (see how). Что касается вопроса, вы должны перефразировать свой вопрос, а также попытаться переосмыслить это выражение, потому что сейчас просто какая-то логика спагетти, разорванная на суп кода. @Farhad Jabiev: Предоставление рыбы человеку кормит его днем, обучая его, как рыбу кормить его всю жизнь.

+0

'IEqualityComparer ' - это интерфейс для объекта, который выполняет сравнение на двух объектах типа 'T'. –

+0

Я вижу, вы знаете, как печатать ... приятно. –

+0

По imliment Я имею в виду 'override', а также в моем случае я не уверен, как« переопределить GetHashCode », потому что в этом' T' есть тот же тип объекта класса, что и у меня есть два объекта класса diffrent для сравнения. И да, linq немного грубо, но потому что я пытаюсь изучить его, используя разные примеры и пытаясь применить разные способы получить тот же результат. – user2745246

0

Это пример реализации IEqualityComparer. Он должен работать как концепция для вашей цели:

private class PKExclusiveComparer<T> : IEqualityComparer<T> where T : DataRow 
{ 
    public bool Equals(T x, T y) 
    { 
    bool result = true; 
    foreach (DataColumn col in (x as DataRow).Table.Columns) 
    { 
     if (!(x as DataRow).Table.PrimaryKey.Contains(col)) 
     { 
     result &= x[col].Equals(y[col]); 
     } 
    } 
    return result; 
    } 

    public int GetHashCode(T x) 
    { 
    string code = string.Empty; 
    foreach (DataColumn col in (x as DataRow).Table.Columns) 
    { 
     if (!(x as DataRow).Table.PrimaryKey.Contains(col)) 
     { 
     code += x[col].ToString(); 
     } 
    } 
    return code.GetHashCode(); 
    } 
} 
+0

Ouups, некоторые ошибки формирования. Во всяком случае, моя идея, которую я использовал сотни раз, - это получить «уникальную строку», а затем получить хэш. – S22

+0

Извините, но как он может работать. Здесь 'T' является типом' DataRow', который является одним типом. Моя проблема заключается в том, что мой тип 'T' может быть либо« TestA », либо« TestB »не одним типом, как указано выше. Поскольку «GetHashcode» получает только один тип в качестве аргумента, я не уверен, как передать свой два разных типа класса в «GetHashCode». – user2745246

+0

Ну, как я уже сказал, это концепция, а не точное решение для вашего дела. – S22

Смежные вопросы