我正在运行以下表达式,以根据Id
获取2个集合之间的增量,并确保整体结果仅包含“有效/已启用”记录:
//Returns the right records but all IsEnabled = false
var newRecords = allRecordsFromA.Where(a => !(allRecordsFromB.Any(b => ((b.Id == a.Id) && a.IsEnabled)))).ToList();
上述结果会返回A
中不在B
,中的所有正确记录,但所有记录都标记为IsEnabled = false
。真正令人困惑的部分是我在应用程序的另一部分中的其他2个集合上使用 exact 相同的表达式,并且工作。我收回所有正确的记录,它们都被标记为.IsEnabled == true
这对我来说毫无意义。我甚至复制了它并且它不起作用。
但是,如果我改为两步过程,我会得到我想要的结果:
//Works
var newRecords = allRecordsFromA.Where(a => !(allRecordsFromB.Any(b => (b.Id == a.Id)))).ToList();
var results = newRecords.Where(x => x.IsEnabled).ToList();
我在想第一个表达式中的操作顺序是错误的,返回记录时!
被应用于IsEnabled
但我看不到它。我的第一个表达式中返回带有IsEnabled == false
的记录的错误是什么?
答案 0 :(得分:3)
我认为你的括号不在你认为的位置。具体来说,a.IsEnabled
位于Any
语句中,然后被否定。
allRecordsFromB.Any(b => ((b.Id == a.Id) && a.IsEnabled))
这为您提供了与第二个示例完全不同的逻辑。我将a.IsEnabled
移到Where
的开头,删除一些不必要的括号以澄清事情。
var newRecords = allRecordsFromA.Where(a => a.IsEnabled &&
!allRecordsFromB.Any(b => b.Id == a.Id)).ToList();
请注意,如果您拥有大型数据集,或者认为以下方法更清晰,则可以通过创建b.Id
的哈希集来加快速度。 (或通过某种类型的联接,内部会做同样的事情)
var bIds = new HashSet<int>(allRecordsFromB.Select(b => b.Id));
var newRecords = allRecordsFromA.Where(a => a.IsEnabled &&
!bIds.Contains(a.Id)).ToList();
答案 1 :(得分:2)
检查a是否已启用在Any
内,即否定。因此,如果条件b.Id == a.Id
(b
)和allRecordsFromB
中的某些a.IsEnabled
条件都为真,那么该元素将不成为结果的一部分。如果其中一个是假的,它将成为结果的一部分。
因为这与您想要的相反,您应该将IsEnabled
支票移到Any.
答案 2 :(得分:1)
我认为问题的一部分是你的Linq声明难以阅读而且这种目的无法实现。你可能想要考虑这样的事情:
var collectionA = new List<Record>();
var collectionB = new List<Record>();
var results = collectionA.Intersect(collectionB).Where(x => x.IsEnabled);
您必须实现Equals方法:
public class Record
{
public int Id { get; set; }
public bool IsEnabled { get; set; }
protected bool Equals(Record other)
{
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Record) obj);
}
public override int GetHashCode()
{
return Id;
}
}
或者创建一个Comparer并将其传递给Intersect方法:
public class RecordComparer : IEqualityComparer<Record>
{
public bool Equals(Record x, Record y)
{
return x.Id == y.Id;
}
public int GetHashCode(Record obj)
{
return obj.GetHashCode();
}
}