2016-12-20 6 views
1

Я читал о интерфейсе IEqualityComparer. Вот мой код (который говорит больше, чем тысяча слов)Linq сравнить два ObservableCollection <T> с исключением

static void Main(string[] args) 
{ 
    var Send = new ObservableCollection<ProdRow>() { 
     new ProdRow() { Code = "8718607000065", Quantity = 1 }, 
     new ProdRow() { Code = "8718607000911", Quantity = 10 } 
    }; 
    var WouldSend = new ObservableCollection<ProdRow>() { 
     new ProdRow() { Code = "8718607000065", Quantity = 1 }, 
     new ProdRow() { Code = "8718607000072", Quantity = 1 }, 
     new ProdRow() { Code = "8718607000256", Quantity = 1 }, 
     new ProdRow() { Code = "8718607000485", Quantity = 1 }, 
     new ProdRow() { Code = "8718607000737", Quantity = 1 }, 
     new ProdRow() { Code = "8718607000911", Quantity = 20 } 
    }; 

    //var sendToMuch = Send.Except(WouldSend).ToList(); 
    //var sendToLittle = WouldSend.Except(Send).ToList(); 

    //if (sendToMuch.Any() || sendToLittle.Any()) 
    // var notGood = true; 
    //else 
    // var okay = true; 

    var sendToMuch = Send.ToList(); 
    var sendToLittle = WouldSend.ToList(); 

    foreach (var s in Send) { 
     var w = WouldSend.FirstOrDefault(d => d.Code.Equals(s.Code)); 

     if (w != null) { 
      if (w.Quantity == s.Quantity) { 
       sendToMuch.Remove(s); 
       sendToLittle.Remove(w); 
       continue; 
      } 
      if (w.Quantity > s.Quantity) { 
       sendToLittle.Single(l => l.Code == w.Code).Quantity = (w.Quantity - s.Quantity); 
       sendToMuch.Remove(s); 
      } else { 
       sendToMuch.Single(l => l.Code == w.Code).Quantity = (s.Quantity - w.Quantity); 
       sendToLittle.Remove(s); 
      } 
     } else { 
      sendToMuch.Add(s); 
     } 
    } 
} 

комментируемая линия, где то, что я надеялся, что будет работать ... материал ниже с тем, что я закончил с.

В качестве ссылки, вот мой ProdRow класс:

class ProdRow : INotifyPropertyChanged, IEqualityComparer<ProdRow> 
{ 
    private string _code; 
    private int _quantity; 
    public string Code { 
     get { return _code; } 
     set { 
      _code = value; 
      OnPropertyChanged("Code"); 
     } 
    } 
    public int Quantity { 
     get { return _quantity; } 
     set { 
      _quantity = value; 
      OnPropertyChanged("Quantity"); 
     } 
    } 

    private void OnPropertyChanged(string v) { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(v)); 
    } 

    public new bool Equals(object x, object y) { 
     if (((ProdRow)x).Code.Equals(((ProdRow)y).Code) && ((ProdRow)x).Quantity == ((ProdRow)y).Quantity) 
      return true; 
     else 
      return false; 
    } 
    public int GetHashCode(object obj) { 
     return obj.GetHashCode(); 
    } 
    public bool Equals(ProdRow x, ProdRow y) { 
     if (x.Code.Equals(y.Code) && x.Quantity == y.Quantity) 
      return true; 
     else 
      return false; 
    } 
    public int GetHashCode(ProdRow obj) { 
     throw new NotImplementedException(); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
} 

Я не ожидал, что комментировал часть на работу, потому что он не может знать, чтобы уменьшить Int количества и т.д., но я хотел бы, если знаю, это более эффективный способ сделать это, а затем решение, которое я использовал (ниже прокомментированных строк). Возможно, сгладить коллекцию как string[]?

P.S. Извините за «PascalCase» из Send и WouldSend

+1

Что именно делать Вы хотите сделать ? У вас есть 2 сборника, что вы хотите получить? – mybirthname

+0

например 'sendToLittle' должен иметь прокрутку с кодом« 8718607000911 », а количество 10 и' sendToMuch' должно быть пустым. то есть вывод кода, который не комментируется. –

+0

Итак, как я понимаю, вы хотите что-то вроде (внешнего) соединения в «Кодексе» с Diff (substraction) на «Quantity» и фильтр с комбинированной величиной, не равной нулю? – grek40

ответ

3

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

Правый интерфейс для строго типизированного сравнения равен IEquatable<T>. Тем не менее, в вашем случае все, что вам нужно, это переопределение Object «s Equals(object) и GetHashCode():

public new bool Equals(object obj) { 
    if (obj == this) return true; 
    var other = obj as ProdRow; 
    if (other == null) return false; 
    return Code.Equals(other.Code) && Quantity == other.Quantity; 
} 
public int GetHashCode() { 
    return 31*Code.GetHashCode() + Quantity; 
} 

Что касается вычислительных величин идет, вы можете сделать это с отрицательными числами и GroupBy:

var quantityByCode = WouldSend.Select(p => new {p.Code, p.Quantity}) 
    .Concat(Send.Select(p => new {p.Code, Quantity = -p.Quantity})) 
    .GroupBy(p => p.Code) 
    .ToDictionary(g => g.Key, g => g.Sum(p => p.Quantity)); 
var tooLittle = quantityByCode 
    .Where(p => p.Value > 0) 
    .Select(p => new ProdRow {Code = p.Key, Quantity = p.Value}) 
    .ToList(); 
var tooMuch = quantityByCode 
    .Where(p => p.Value < 0) 
    .Select(p => new ProdRow {Code = p.Key, Quantity = -p.Value}) 
    .ToList(); 
+0

Спасибо, что интерфейс работает лучше и отлично видит первый продукт. Но для второго он должен уменьшить количество. как сказал, возможно, мне нужно сначала сгладить коллекцию, чтобы получить две коллекции предметов, которые были отправлены слишком много или слишком мало. –

+0

Действительно, как дополнение Linq! Благодаря! Единственное, что можно назвать именованием tooMuch и tooLittle :) –

+0

@JPHellemons Done. Благодаря! – dasblinkenlight

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