I have two generic lists of type T. Both lists contain same type, and I’d like to create a third list (or a filtered version of list 2) based on the items in list two that do not exist in List 1, based on the ID of each item.
Each list holds a “Package” object, which has an ID property.
Right now I mocked up the code using For Each loops, which I know is horrible (the Big O is constant time) so I’d like a more efficent method.
this code is in VB per project requirments, but I prefer C# – so either code sample would work for me.
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
What is a nice and clean LINQ or Lamda way of doing this filtering? What is the Big O of my method and what would be the Big O of the proposed method (just to satify my curiosity).
Thanks
LINQ Except Method
This would be the cleanest way, as suggested by Maxim and svick but requires an overridden Equals method which equals on ID or you have to provide a comparer (see svicks answer).
Resources
Many LINQ samles can be found in the msdn at http://msdn.microsoft.com/en-us/vcsharp/aa336746
I’ll leave the initial parts of my answer for reference:
Brute force way:
should do the trick. You just have to translate the lambda syntax to vb.net.
This query will filter all items from
stockPackageListwhich IDs are not present in all items ofpackageList.You may invert the query:
The
Anyquery will return true if any item inpackageListhas a matching id. This query should run a little faster because it has not to traverse the whole collection, asAllhas to.Using Eqality:
If your package object implements
IEquatable<Package>you can shorten the code down toUsing a Hash Set:
If you want to use a hash set you can do
This saves computation time when the lists become large, as faester and Ivan Danilov pointed out.