.NET Generics - 比较两个列表和过滤器:最佳实践

noc*_*ier 1 .net c# vb.net generics list

我有两个类型为T的通用列表.两个列表包含相同的类型,我想根据列表2中列表1中不存在的项目创建第三个列表(或列表2的过滤版本)在每个项目的ID上.

每个列表都包含一个"Package"对象,该对象具有ID属性.

现在我使用For Each循环模拟代码,我知道这很糟糕(Big O是恒定的时间)所以我想要一种更有效的方法.

这个代码是按照项目要求的VB,但我更喜欢C# - 所以任何一个代码示例都适合我.

Private Sub RemoveStockPackagesFromSelection()

    Dim p As Package
    Dim packageList As List(Of Package) = New List(Of Package)
    Dim stockPackageList As List(Of Package) = New List(Of Package)
    Dim result As List(Of Package) = New List(Of Package)

    ' Fill list with User's Packages
    For i As Integer = 0 To ListBox2.Items.Count - 1
        p = New Package
        p.Id = CInt(ListBox2.Items(i).Value)
        p.Name = ListBox2.Items(i).Text
        packageList.Add(p)
    Next

    ' Fill list with Stock Packages to compare:
    Dim ds As DataSet = DAL.GetStandardPackages()

    For Each dr As DataRow In ds.Tables(0).Rows
        p = New Package
        p.Id = CInt(dr.Item("id"))
        stockPackageList.Add(p)
    Next

    ' Do Compare and Filter
    For Each p1 As Package In packageList
        For Each p2 As Package In stockPackageList
            If Not p1.Id = p2.Id Then
                result.Add(p2)
            End If
        Next
    Next

    ' Here is our new trimmed list:
    Response.Write(result.Count)

End Sub
Run Code Online (Sandbox Code Playgroud)

什么是一个漂亮而干净的LINQ或Lamda进行此过滤的方式?什么是我的方法的大O和拟议方法的大O(只是为了满足我的好奇心).

谢谢

Zeb*_*ebi 8

LINQ除了方法

这是最干净的方式,正如Maxim和svick所建议的那样,但是需要一个等于ID的重写Equals方法,或者你必须提供一个比较器(参见svicks答案).

var result = stockPackageList.Except(packageList).ToList();
Run Code Online (Sandbox Code Playgroud)

资源 许多LINQ samles可以在msdn中找到,网址为:http://msdn.microsoft.com/en-us/vcsharp/aa336746


我将留下我的答案的初始部分以供参考:

蛮力方式:

var result = stockPackageList
              .Where(x => packageList.All(package => x.Id != package.Id))
              .ToList();
Run Code Online (Sandbox Code Playgroud)

应该做的伎俩.您只需将lambda语法翻译为vb.net即可.

此查询将过滤所有项目stockPackageList中不存在ID的所有项目packageList.

您可以反转查询:

var result = stockPackageList
              .Where(x => packageList.Any(package => x.Id == package.Id) == false)
              .ToList();
Run Code Online (Sandbox Code Playgroud)

Any如果任何项目的查询将返回真packageList有一个匹配的ID.此查询应该运行得快一点,因为它不必遍历整个集合All.

使用Eqality:

如果您的包对象实现,IEquatable<Package>您可以缩短代码

var result = stockPackageList
              .Where(x => packageList.Contains(x) == false)
              .ToList();
Run Code Online (Sandbox Code Playgroud)

使用哈希集:

如果您想使用哈希集,您可以这样做

var hash = new HashSet<string>(packageList.Select(x=>x.Id));
var result = stockPackageList.Where(x => hash.Contains(x.Id) == false).ToList();
Run Code Online (Sandbox Code Playgroud)

正如费斯特和伊万丹尼洛夫指出的那样,当列表变大时,这节省了计算时间.


Max*_*xim 7

无法真正读懂你的VB代码,但如果你想让l2中的项目不在l1中 -

她是一个C#代码示例

   public class SomeObject
    {
        public string ID { get; set; }
    }

    public class SomeObjectComparer : IEqualityComparer<SomeObject>
    {
        public bool Equals(SomeObject x, SomeObject y)
        {
            return x.ID == y.ID;
        }

        public int GetHashCode(SomeObject obj)
        {
            return obj.ID.GetHashCode();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<SomeObject> l1, l2;
            // lists init ...

            IEqualityComparer<SomeObject> comparer = new SomeObjectComparer();

            List<SomeObject> l3 = l2.Except(l1, comparer).ToList();

        }
    }
Run Code Online (Sandbox Code Playgroud)

  • @Ivan`Except`在内部使用Set操作 (3认同)