使用All()时,Lambda表达式不返回正确的结果

时间:2016-07-19 13:27:08

标签: c# linq lambda

我有这堂课:

public class Change()
{
    public int Id {get; set;}
    public decimal Price {get; set;}
}

我有2个列表oldPricesnewPrices。两个列表包含相同的项目,但不同的实例。

newPrices中的某些项目有不同的价格,所以要获取我正在做的更改价格列表:

var list = newPrices
             .Where(x => oldPrices.All(p => p.Price != x.Price))
             .ToDictionary(x => x.Id, x => x.Price);

这个表达式应该是正确的,但即使有变化,列表也是空的。

我错过了什么?

5 个答案:

答案 0 :(得分:2)

如果所有条件都为真,则

Enumerable.All返回true。那不是你想要检查的。您希望获得与旧价格不同的所有新价格。

您必须先Id加入两个列表才能比较价格:

var joined = from np in newPrices
             join op in oldPrices
             on np.Id equals op.Id
             where np.Price != op.Price
             select np;
var newPricesById = joined.ToDictionary(p => p.Id, p => p.Price);

答案 1 :(得分:1)

All检查oldPrices所有元素的条件是否为真。我想你想要的是检查具有相同ID的项目的价格是否已经改变。

我建议先将旧列表转换为字典:

var oldPricesDic = oldPrices.ToDictionary(x => x.Id, x => x.Price);

然后像这样过滤新列表:

var list = newPrices
             .Where(x => !oldPricesDic.ContainsKey(x.Id) ||
                         oldPricesDic[x.Id] != x.Price)
             .ToDictionary(x => x.Id, x => x.Price);

现在返回包含所有已更改(或新)项目的字典。

答案 2 :(得分:1)

你可以让Change class IEquatable<Change>允许一个简单的LINQ except()调用:

void Main()
{
    var oldPrices = new List<Change> {
        new Change { Id = 1, Price = 1.5M },
        new Change { Id = 2, Price = 5.0M }
    };

    var newPrices = new List<Change> {
        new Change { Id = 1, Price = 1.5M },
        new Change { Id = 2, Price = 5.75M }
    };

    var list = newPrices.Except(oldPrices).ToDictionary(x => x.Id, x => x.Price);
}

public class Change : IEquatable<Change>
{
    public int Id {get; set;}
    public decimal Price {get; set;}

    public bool Equals(Change other)
    {
        if (Object.ReferenceEquals(other, null)) return false;
        if (Object.ReferenceEquals(this, other)) return true;
        return Id.Equals(other.Id) && Price.Equals(other.Price);
    }

    public override int GetHashCode()
    {
        int hashId = Id.GetHashCode();
        int hashPrice = Price.GetHashCode();
        return hashId ^ hashPrice;
    }
}

答案 3 :(得分:0)

您也可以尝试这2个左外连接解决方​​案..

  var pricesFromLeftJoin =
                    (from np in newPrices
                     join op in oldPrices on np.Id equals op.Id into subOldPrices
                     from subPrice in subOldPrice.DefaultIfEmpty()
                     where subPrice == null || (subPrice != null && subPrice .Price != np.Price)
                     select np).ToDictionary(x => x.Id, x => x.Price);


  var pricesFromLeftJoin_compactForm =
                (from np in newPrices
                 from op in oldPrices.Where(op => (op.Id == np.Id)).DefaultIfEmpty() 
                 where op == null || (op != null && op.Price != np.Price)
                 select np).ToDictionary(x => x.Id, x => x.Price);

答案 4 :(得分:0)

正如其他人指出All要求序列的所有元素都满足条件。它也可以使用Enumerable.Zip方法完成:

var dictionary = newPrices.OrderBy(c => c.Id)
                .Zip(oldPrices.OrderBy(p => p.Id), (c, p) => p.Price != c.Price ? c : null)
                .Where(c => c != null).ToDictionary(c => c.Id, c => c.Price);
相关问题