2016-12-20 1 views
1

Ich habe über die IEqualityComparer Schnittstelle gelesen. Hier ist mein Code (die mehr als tausend Worte sagt)Linq vergleichen zwei ObservableCollection <T> mit Ausnahme

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

Die kommentierten Zeilen in dem, was ich hoffte, dass das funktionieren würde ... das Zeug unten mit dem, was ich am Ende mit.

Als Referenz hier ist meine ProdRow Klasse:

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

ich nicht der kommentierten Teil der Arbeit erwartet hat, weil es nicht die int der Menge usw. zu verringern, kann wissen, aber ich würde, wenn wissen, es ist eine effizientere Möglichkeit, dies zu tun, dann die Lösung, die ich verwendet habe (unter den kommentierten Zeilen). Vielleicht die Sammlung wie eine string[] glätten?

P.S. Sorry für die „Pascal“ von Send und WouldSend

+1

Was genau du möchtest machen ? Du hast diese 2 Sammlung, was willst du sein? – mybirthname

+0

zum Beispiel 'sendToLittle' sollte ein Prodrow mit dem Code" 8718607000911 "haben und die Menge 10 und' sendToMuch' sollte leer sein. d.h. die Ausgabe des Codes, der nicht kommentiert ist. –

+0

Also, wie ich verstehe, wollen Sie etwas wie eine (äußere) Join auf "Code" mit einem Diff (Subtraktion) auf "Menge" und ein Filter auf kombinierte Menge ungleich Null? – grek40

Antwort

3

IEqualityComparer<T> ist nicht die richtige Schnittstelle für eine Klasse, deren Instanzen Sie vergleichen wollen zu implementieren. IEqualityComparer<T> Implementierungen sind zum Erstellen von Objekten, die Vergleiche von außerhalb der der Objekte verglichen werden, die wichtig wird, wenn Sie neu definieren müssen, was es für zwei Objekte ohne Zugriff auf den Code dieser Objekte oder wann bedeutet Sie müssen je nach Kontext unterschiedliche Semantik für die Gleichheit verwenden.

Die richtige Schnittstelle für den stark typisierten Gleichheitsvergleich ist IEquatable<T>. in Ihrem Fall alles, was Sie Object ‚s Equals(object) und GetHashCode() ist zwingende Allerdings müssen:

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

Soweit Rechen Mengen geht, können Sie es mit negativen Zahlen tun und 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

Dank dieser Schnittstelle funktioniert es besser und sieht das erste Produkt perfekt. Aber für die zweite sollte es die Menge reduzieren. Wie gesagt, vielleicht muss ich die Sammlung zuerst abflachen, um zwei Sammlungen von Gegenständen zu erhalten, die zu viel oder zu wenig gesendet wurden. –

+0

Wirklich wie Ihre Linq Ergänzung! Vielen Dank! Einzige Sache ist, dass die Benennung von tooMuch und tooLittle umgestellt werden sollte :) –

+0

@JPHellemons Fertig. Vielen Dank! – dasblinkenlight

Verwandte Themen