繁体   English   中英

如何使用Linq to Objects优化检查列表中所有添加,删除或更新的项目?

[英]How do I optimize checking for any added, deleted or updated items on a list with Linq to Objects?

我需要检查是否对通用集合中存在的项目进行了任何操作(插入,删除或更新)。 我有一个包含原始对象的列表和一个包含新对象的列表。 具有相同ID的两个对象的引用将不同。

现在,我能够解决问题,但是执行了3个操作。 这是我的代码:

var oldList = new List<MyClass>();
var newList = new List<MyClass>();

//Search for items on the new list that are not present on the old one
var addedItems = newList.Where(item => !oldList.Select(x => x.Id).Contains(item.Id));

//Search for items on the old list that are not present on the new one
var deletedItems = oldList.Where(item => !newList.Select(x => x.Id).Contains(item.Id));

//Search for items present on both lists, but with any property changed
var updatedItems = from x in oldList
                   join y in newList on x.Id equals y.Id
                   where x.Name != y.Name ||
                         x.Description != y.Description ||
                         x.Quantity != y.Quantity
                   select new { OriginalEntity = x, NewEntity = y };

bool anyChanges = addedItems.Count() > 0   ||
                  deletedItems.Count() > 0 ||
                  updatedItems.Count() > 0;

这段代码有效,但是我想知道是否有可能以更简洁或更快速(更少的操作)的方式实现结果。

我知道我可以在MyClass上实现IEquatable <T>,但请考虑一下目前尚不可能(仅是因为我想确定是否有解决方案,何时确实无法实现)。 无论如何,这将允许我使用“ Except”并轻松检测到插入或删除,但不能检测到更新(除非我遗漏了一些东西)。

另外,我只是想指出,SO上存在很多类似问题,但我还没有发现与同时检测插入,删除和更新相关的任何原因(我为什么要发布此消息)。

提前致谢!

通常,您只需要缓存+更好的数据结构。

var oldList = new List<MyClass>();
var newList = new List<MyClass>();

// O(1) lookups vs O(N) lookups
var oldListIds = new HashSet<int>(oldList.Select(x => x.Id));
var newListIds new HashSet<int>(newList.Select(x => x.Id));

//Search for items on the new list that are not present on the old one
var addedItems = newList.Where(item => !oldListIds.Contains(item.Id));

//Search for items on the old list that are not present on the new one
var deletedItems = oldList.Where(item => !newListIds.Contains(item.Id));

//Search for items present on both lists, but with any property changed
var updatedItems = from x in oldList
                   join y in newList on x.Id equals y.Id
                   where x.Name != y.Name ||
                         x.Description != y.Description ||
                         x.Quantity != y.Quantity
                   select new { OriginalEntity = x, NewEntity = y };

// Use .Any() instead of .Count() so we stop after first item
bool anyChanges = addedItems.Any()   ||
                  deletedItems.Any() ||
                  updatedItems.Any();

这样的事情怎么样:

// determines if evey item in listA has as a match in listB
static bool Matches(List<MyClass> listA, List<MyClass> listB)
{
    var matches = listA.GroupJoin(listB, a => a.Id, b => b.Id,
        (a, b) => b.Any(c => c.Name == a.Name && c.Description == a.Description && c.Quantity == a.Quantity));

    return matches.All(m => m);
}

如果B与A联接,则执行GroupJoin()返回布尔值。然后执行All(),以查看所有联接是否返回true。

然后可以这样称呼它:

bool equal = Matches(oldList, newList) && Matches(newList, oldList);

这将返回一个布尔值,指示oldList中的所有内容是否都连接到newList中而newList中的所有内容是否都连接到oldList中。

我不确定这是否会比其他建议快,但肯定是更少的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM