Lambda表达式在使用All()时未返回正确的结果
本文关键字:返回 结果 表达式 All Lambda | 更新日期: 2023-09-27 17:57:35
我有这个类:
public class Change()
{
public int Id {get; set;}
public decimal Price {get; set;}
}
我有两个列表oldPrices
和newPrices
。两个列表都包含相同的项目,尽管实例不同。
newPrices
中的一些商品有不同的价格,所以为了获得更改价格的列表,我正在做:
var list = newPrices
.Where(x => oldPrices.All(p => p.Price != x.Price))
.ToDictionary(x => x.Id, x => x.Price);
此表达式应该是正确的,但即使有更改,列表也是空的。
我错过了什么?
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);
All
检查oldPrices
中所有元素的条件是否为true。我想你想要的是检查具有相同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);
这将返回一个包含所有已更改(或新)项的词典。
您可以使Change类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;
}
}
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);
您也可以尝试这两个左外部联接解决方案。。
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);