C# 按特定属性比较两个大型项目列表

我有两个大型项目列表,它们的类看起来像这样(两个列表都属于同一类型):


public class Items

{

 public string ItemID { get; set; }

 public int QuantitySold { get; set; }

}



var oldList = new List<Items>(); // oldList


var newList = new List<Items>(); // new list

旧列表包含来自数据库的项目,新列表表示从 API 获取的项目;


两个列表都可能非常大,每个列表包含 10000 多个项目(总共 20000 个)


我需要将 newList 中的项目与“oldList”中的项目进行比较,并查看哪些项目具有相同的 itemID 值,具有不同的“QuantitySold”值,而那些具有不同“QuantitySold”值的项目应存储在名为“不同数量的项目”。


我可以简单地做双 foreach 列表并比较值,但由于两个列表都很大,双 foreach 循环的性能很糟糕,我做不到......


有人可以帮我解决这个问题吗?


@YamamotoTetsua 我已经在使用 IEqualityComparer 来获得所需的结果,但是它并没有给出我期望的结果。这就是为什么......我有一个看起来像这样的第一个 IEqualityComparer:


 public class MissingItemComparer : IEqualityComparer<SearchedUserItems>

    {

        public static readonly IEqualityComparer<SearchedUserItems> Instance = new MissingItemComparer();


        public bool Equals(SearchedUserItems x, SearchedUserItems y)

        {

            return x.ItemID == y.ItemID;

        }


        public int GetHashCode(SearchedUserItems x)

        {

            return x.ItemID.GetHashCode();

        }

    }

这个 IEqualityComparer 的使用基本上给了我来自 newList 的项目,这些项目在我的数据库中不存在,如下所示:


var missingItems= newItems.Except(competitor.SearchedUserItems.ToList(), MissingItemComparer.Instance).ToList();

现在在此列表中,我将列出 API 中的新项目列表,并且不存在于我的数据库中...


第二个 IEqualityComparer 基于旧列表和新列表中不同的 QuantitySold:


public class ItemsComparer : IEqualityComparer<SearchedUserItems>

    {

        public static readonly IEqualityComparer<SearchedUserItems> Instance = new ItemsComparer();

        public bool Equals(SearchedUserItems x, SearchedUserItems y)

        {

            return (x.QuantitySold == y.QuantitySold);

        }

        public int GetHashCode(SearchedUserItems x)

        {

            return x.ItemID.GetHashCode();

        }

    }

使用示例:

var differentQuantityItems = newItems.Except(competitor.SearchedUserItems.ToList(), ItemsComparer.Instance).ToList();

他们确实从我的 oldList 中丢失了......但是第二个 IEQualityComparer 也会将这些项目作为 differentQuantity 项目返回,它们确实是,但它们不存在于 oldList 中。所以它们不应该包含在第二个列表中.


繁星coding
浏览 207回答 4
4回答

RISEBY

这是 LINQ&nbsp;Join的完美候选人:var differentQuantityItems =&nbsp; &nbsp; (from newItem in newList&nbsp; &nbsp; &nbsp;join oldItem in oldList on newItem.ItemID equals oldItem.ItemID&nbsp; &nbsp; &nbsp;where newItem.QuantitySold != oldItem.QuantitySold&nbsp; &nbsp; &nbsp;select newItem).ToList();这将返回所有具有不同 QuantitySold 的对应旧项目的新项目。如果您还想包含没有相应旧项目的新项目,请使用左外连接:var differentQuantityItems =&nbsp; &nbsp; (from newItem in newList&nbsp; &nbsp; &nbsp;join oldItem in oldList on newItem.ItemID equals oldItem.ItemID into oldItems&nbsp; &nbsp; &nbsp;from oldItem in oldItems.DefaultIfEmpty()&nbsp; &nbsp; &nbsp;where oldItem == null || newItem.QuantitySold != oldItem.QuantitySold&nbsp; &nbsp; &nbsp;select newItem).ToList();在这两种情况下,连接运算符都用于快速关联具有相同 ItemID 的项目。然后您可以比较 QuantitySold 或任何其他属性。

开心每一天1111

即使根本没有匹配项,此代码也将在不到一秒的时间内运行(如果一切都匹配,也将在不到一秒的时间内运行)。它将返回两个列表中存在的所有项目(即相同ItemID)但具有不同的QuantitySold.using System;using System.Collections.Generic;using System.Linq;namespace ConsoleApp5{&nbsp; &nbsp; class Program&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public class Items&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public string ItemID { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public int QuantitySold { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; static void Main(string[] args)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Sample data&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var oldList = new List<Items>();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oldList.AddRange(Enumerable.Range(0, 20000).Select(z => new Items() { ItemID = z.ToString(), QuantitySold = 4 }));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var newList = new List<Items>();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newList.AddRange(Enumerable.Range(0, 20000).Select(z => new Items() { ItemID = z.ToString(), QuantitySold = 5 }));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var results = oldList.Join(newList,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left => left.ItemID,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right => right.ItemID,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (left, right) => new { left, right })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Where(z => z.left.QuantitySold != z.right.QuantitySold).Select(z => z.left);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine(results.Count());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.ReadLine();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}的使用z.left意味着只有一个项目将被退回 - 如果你想要旧的和新的,而不是使用:var results = oldList.Join(newList,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left => left.ItemID,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right => right.ItemID,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (left, right) => new { left, right })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Where(z => z.left.QuantitySold != z.right.QuantitySold)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Select(z => new[] { z.left, z.right })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .SelectMany(z => z);

POPMUISE

从大 O 复杂性的角度来看,仅比较嵌套 for 循环中的列表将属于O(n*m)类,其中n是数据库中列表的大小,而m是列表的大小从 API 获取。为了提高性能,您可以做的是对两个列表进行排序,这将花费O(n&nbsp;log&nbsp;(n) + m&nbsp;log&nbsp;(m)),然后您可以在O(n + m)中找到新项目。因此,您的算法的整体复杂性将属于O(n&nbsp;log&nbsp;(n) + m&nbsp;log&nbsp;(m))类。这是一个关于所花费时间的想法,将二次解与超线性解进行比较。

函数式编程

您可以考虑使用带有自定义编写的 except 子句,IEqualityComparer如下所示var oldList = new List<Item>(); // oldListvar newList = new List<Item>(); // new listvar distinctList = newList.Except(oldList,new ItemEqualityComparer()).ToList();class ItemEqualityComparer : IEqualityComparer<Item>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public bool Equals(Item i1, Item i2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (i1.ItemID == i2.ItemID && i1.QuantitySold != i2.QuantitySold)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public int GetHashCode(Item item)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return item.ItemID.GetHashCode();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }public class Item&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public string ItemID { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public int QuantitySold { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; }
打开App,查看更多内容
随时随地看视频慕课网APP