Linq将两个ObservableCollection <t>与Except进行比较

时间:2016-12-20 13:48:56

标签: c# linq observablecollection iequalitycomparer

我已阅读有关IEqualityComparer界面的信息。这是我的代码(说的话超过千言万语)

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

我没想到评论的部分可以工作,因为它无法知道减少数量等等但是我想知道是否有更有效的方法来做到这一点然后我使用的解决方案(在评论下面)线)。也许像string[]

那样压缩集合

P.S。对于SendWouldSend

的“PascalCase”感到抱歉

1 个答案:

答案 0 :(得分:3)

IEqualityComparer<T>不是要为其实例进行比较的类实现的正确接口。 IEqualityComparer<T>实现用于创建与正在比较的对象的外部进行比较的对象,当您需要重新定义两个对象无法访问时它意味着什么时,这变得很重要对于这些对象的代码,或者当您需要根据上下文使用不同的语义进行相等时。

强类型相等比较的正确接口是IEquatable<T>。但是,在您的情况下,您只需要覆盖Object 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();