2016-06-14 2 views
1

Я знаю, что подобные вопросы уже прошли эту правление, но я не мог найти тот, который отвечает на мой вопрос.Linq сравнить 2 списков объектов

У меня есть 2 list<myObject> с 3 объектами.

Класс:

public int MeterID {get; set;} 
    public string Datum { get; set; } 
    public int NumberOfValues { get; set; } 

    public myObject(int meterID, string datum, int numberOfValues) 
    { 
     this.ID= ID; 
     this.Datum = datum; 
     this.NumberOfValues = numberOfValues; 
    } 

Я хочу сравнить эти списки, основанные на следующих 2-х значений ID, Datum, но я хочу, чтобы результат все равно будет List<MyObject> Так что, когда мой объект находится в lišta и LISTB он не должен показать в newList после выполнения следующей Linq заявление

var newList = ListA.Select(x => new { x.ID, x.Datum }).Except(ListB.Select(z => new { z.ID, z.Datum })); 

заявление не дает мне список MyObject, но со списком с только ID и данности. Мне также нужно, чтобы свойство NumberOfValues ​​из ListA было в newList.

Есть ли способ достичь этого с помощью linq?

+0

Почему '' Datum' String', а не 'DateTime'? –

ответ

6

Я хотел бы сделать это так:

var result = ListA.Where(a => 
       ListB.All(b => b.ID != a.ID || b.Datum != a.Datum)).ToList(); 

Это принимает все элементы из ListA, для которых все элементы ListB отличаются (для определения различны).

Если вы хотите иметь элементы ListB, которые не находятся в ListA вы можете объединить результаты:

var result = ListA.Where(a => 
       ListB.All(b => b.ID != a.ID || b.Datum != a.Datum)). 
       Concat(ListB.Where(b => 
         ListA.All(a => b.ID != a.ID || b.Datum != a.Datum)). 
      ToList(); 
+0

Похоже, именно это я и искал. – Proliges

+0

Curios: Почему вы помещаете точку в конец строки, а не на вторую строку? (exmpl: ListA.Where (x => x> y). [newline] FirstOrDefault() вместо ListA.Wjere (x => x> y) [newline] .FirstOrDefault. Я думаю, это делает его намного яснее по сравнению с вашим стиль, что заявление продолжается – Mafii

+1

@Mafii вопрос вкуса, у меня часто возникают проблемы с форматированием кода для SO, особенно длинными linq «однострочными». –

2

Другой вариант заключается в использовании Enumerable.Except() с IEqualityComparer, чтобы исключить элементы из listB

public class MyObject 
{ 
    public int MeterID { get; set; } 
    public string Datum { get; set; } 
    public int NumberOfValues { get; set; } 

    public MyObject(int meterID, string datum, int numberOfValues) 
    { 
     this.MeterID = meterID; 
     this.Datum = datum; 
     this.NumberOfValues = numberOfValues; 
    } 
} 

public class MyObjectEqualityComparer : EqualityComparer<MyObject> 
{ 
    public override bool Equals(MyObject x, MyObject y) 
    { 
     return x.MeterID == y.MeterID 
      && x.Datum == y.Datum; 
    } 

    public override int GetHashCode(MyObject obj) 
    { 
     return obj.MeterID^obj.Datum.GetHashCode(); 
    } 
} 

При кодировании критериев сравнения во внешнем объекте упрощается повторное использование его в другом месте, а также упрощение изменений.

[TestClass] 
public class CompareListsFixture 
{ 

    [TestMethod] 
    public void CompareLists() 
    { 
     var listA = new List<MyObject> 
     { 
      new MyObject(1,"A", 5), // Matches with 1/A/1 
      new MyObject(1,"B", 4), 
      new MyObject(2,"A", 3), // Matches with 2/A/4 
      new MyObject(2,"C", 2), 
     }; 

     var listB = new List<MyObject> 
     { 
      new MyObject(1,"A", 1), 
      new MyObject(2,"A", 4), 
      new MyObject(3,"A", 8), 
     }; 

     var expected = new List<MyObject> 
     { 
      new MyObject(1,"B", 4), 
      new MyObject(2,"C", 2), 
     }; 

     var actual = listA.Except(listB, new MyObjectEqualityComparer()); 

     CollectionAssert.AreEqual(expected, actual.ToList(), new MyObjectComparer()); 

    } 

} 

Мы используем компаратор, чтобы компаратор весь объект в Collection.Assert()

public class MyObjectComparer : Comparer<MyObject> 
{ 
    public override int Compare(MyObject x, MyObject y) 
    { 
     return Format(x).CompareTo(Format(y)); 
    } 

    private static string Format(MyObject obj) 
    { 
     return $"{obj.MeterID}:{obj.Datum}:{obj.NumberOfValues}"; 
    } 
} 
Смежные вопросы