Vb.net 使用.Contains()匹配<;属性的属性;T>;在LINQ查询中
正在寻找有关如何使用Vb.net 使用.Contains()匹配<;属性的属性;T>;在LINQ查询中,vb.net,linq,Vb.net,Linq,正在寻找有关如何使用列表(of T)的.Contains()方法执行LINQ查询的帮助,以基于第一个列表(of T)中的T属性返回第二个列表(of T)中未包含的元素 下面是我编写的一些示例代码,这个场景是虚构的,但概念仍然存在 Module Module1 Sub Main() ' Get all Files in a directory that contain `.mp` in the name Dim AllFiles As List(Of IO
列表(of T)
的.Contains()
方法执行LINQ查询的帮助,以基于第一个列表(of T)
中的T
属性返回第二个列表(of T)
中未包含的元素
下面是我编写的一些示例代码,这个场景是虚构的,但概念仍然存在
Module Module1
Sub Main()
' Get all Files in a directory that contain `.mp` in the name
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("C:\Test\Path").GetFiles("*.mp*").ToList
Dim ValidFiles As New List(Of fileStruct)
' Get all Files that actually have an extension of `.mp3`
AllFiles.ForEach(Sub(x) If x.Extension.Contains("mp3") Then ValidFiles.Add(New fileStruct(prop1:=x.Name, path:=x.FullName)))
' Attempting the get all files that are not listed in the Valid files list
Dim InvalidFiles As IO.FileInfo() = From file As IO.FileInfo In AllFiles Where Not ValidFiles.Contains(Function(x As fileStruct) x.fleInfo.FullName = file.FullName) Select file
' Errors on the `.Contains()` method because I have no idea what I'm doing and I am basically guessing at this point
'Here is the same but instead using the `.Any()` Method
Dim InvalidFiles As IO.FileInfo() = From file As IO.FileInfo In AllFiles Where Not ValidFiles.Any(Function(x As fileStruct) x.fleInfo.FullName = file.FullName) Select file
' This doesn't error out, but all files are returned
End Sub
Public Structure fileStruct
Private _filePath As String
Private _property1 As String
Public ReadOnly Property property1 As String
Get
Return _property1
End Get
End Property
Public ReadOnly Property fleInfo As IO.FileInfo
Get
Return New IO.FileInfo(_filePath)
End Get
End Property
Public Sub New(ByVal prop1 As String, ByVal path As String)
_property1 = prop1
_filePath = path
End Sub
End Structure
End Module
正如其他人所指出的,.Except()是一种更好的方法,但以下是对您的问题的回答:
List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 3, 4, 5 };
List<int> list3 = list1.Where(list1value => !list2.Contains(list1value)).ToList(); // 1, 2
List list1=新列表{1,2,3};
List list2=新列表{3,4,5};
List list3=list1.Where(list1value=>!list2.Contains(list1value)).ToList();//1, 2
以这里的注释为例,使用不同的类型。此查询使用.Any()
List list1=新列表{…};
List list2=新列表{…};
List list3=list1.Where(product=>!list2.Any(vendor=>product.VendorID==vendor.ID)).ToList();
//清单3将包含供应商ID与清单2中任何供应商ID不匹配的产品。
这或多或少是问题中MP3文件列表的直接实现。我确实使用了FileItem
类而不是结构。好的方面是:
' note: EnumerateFiles
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("M:\Music").
EnumerateFiles("*.mp*", IO.SearchOption.AllDirectories).ToList()
Dim goofyFilter As String() = {"g", "h", "s", "a"}
' filter All files to those starting with the above (lots of
' Aerosmith, Steely Dan and Heart)
Dim ValidFiles As List(Of FileItem) = AllFiles.
Where(Function(w) goofyFilter.Contains((w.Name.ToLower)(0))).
Select(Function(s) New FileItem(s.FullName)).ToList()
Dim invalid As List(Of FileInfo)
invalid = AllFiles.Where(Function(w) Not ValidFiles.
Any(Function(a) w.FullName = a.FilePath)).ToList()
这与Sam的答案基本相同,只是您的文件/mp3使用情况不同。所有文件有809项,有效文件有274项。生成的无效列表为535
现在,让我们将其加速50-60倍: 所有文件和有效文件的起始代码相同:
Dim FileItemValid = Function(s As String)
Dim valid As Boolean = False
For Each fi As FileItem In ValidFiles
If fi.FilePath = s Then
valid = True
Exit For
End If
Next
Return valid
End Function
invalid = AllFiles.Where(Function(w) FileItemValid(w.FullName) = False).ToList()
使用秒表
,结果如下:
调用IsValid
函数的普通For/Each循环也会得到类似的结果
如果您不需要其他
文件信息
,您可以将您的所有文件
创建为与接收到的文件结构相同的列表,以便进行属性与属性的比较,使用除了
和包含
:
AllFiles2 = Directory.EnumerateFiles("M:\Music", "*.mp3", IO.SearchOption.AllDirectories).
Select(Function(s) New FileItem(s)).ToList()
现在,您可以使用Contains
获得中等效果:
invalid2 = AllFiles2.Where(Function(w) Not ValidFiles.Contains(w)).ToList()
这也允许您使用,但
更简单、更快:
invalid2 = AllFiles2.Except(ValidFiles).ToList()
即使您需要FileInfo中的其他项目,只要使用文件名,您也可以轻松获取它们,除非CraigW建议使用。你必须做一些投影(选择)才能完成
Dim InvalidFiles as IO.FileInfo() = AllFiles.Select(Function(p) p.FullName).Except(ValidFiles.Select(Function(x) x.fleInfo.FullName)).Select(Function(fullName) New IO.FileInfo(fullName)).ToArray()
注意:这段代码效率不高,可读性也不强,但可以正常工作
但我会选择这样的方式:
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("C:\MyFiles").GetFiles("*.mp*").ToList
Dim ValidFiles As New List(Of fileStruct)
Dim InvalidFiles as New List(Of FileInfo)
For Each fileInfo As FileInfo In AllFiles
If fileInfo.Extension.Contains("mp3") Then
ValidFiles.Add(New fileStruct(prop1:=fileInfo.Name, path:=fileInfo.FullName))
Else
InvalidFiles.Add(fileInfo)
End If
Next
简单、快速、易读。如果您试图获得两个列表之间的差异,请不要使用
Contains()
,使用Except()
@CraigW-.Except()
方法正在寻找与第一个相同类型的第二个集合。在我的例子中,集合不是同一类型的。以您的示例为例,我需要匹配的是list1value.someProperty.value
到list2
,但仍然有所有文件的多次迭代(有效文件一次,无效文件一次)否。如果每个文件都在有效文件中,则所有文件都会迭代一次测试。这至少会导致有效文件的部分迭代,但结果是无效的(文件)。a for/Each循环和Where and anon lambda的IL代码基本上与Steely Dan的LPlus One相同。绝对属于有效文件列表。此外,如果您想真正加快速度,请使用哈希集。实际上,3-4毫秒的速度和它看起来的一样快。ValidFiles的Hashset将Where/Contains的速度从74提高到4ms,但它比其他一些Hashset的速度要慢(只慢一点点)。OP的问题可能是使用哈希集,因为它来自其他地方。我从COM对象收到结构中返回的有效文件列表,然后我需要将这些文件与目录中的文件进行比较,我需要的是所有文件与COM对象返回的文件之间的差异
Where/Contains count: 535, time: 74ms
Except count: 535, time: 3ms
Dim InvalidFiles as IO.FileInfo() = AllFiles.Select(Function(p) p.FullName).Except(ValidFiles.Select(Function(x) x.fleInfo.FullName)).Select(Function(fullName) New IO.FileInfo(fullName)).ToArray()
Dim AllFiles As List(Of IO.FileInfo) = New IO.DirectoryInfo("C:\MyFiles").GetFiles("*.mp*").ToList
Dim ValidFiles As New List(Of fileStruct)
Dim InvalidFiles as New List(Of FileInfo)
For Each fileInfo As FileInfo In AllFiles
If fileInfo.Extension.Contains("mp3") Then
ValidFiles.Add(New fileStruct(prop1:=fileInfo.Name, path:=fileInfo.FullName))
Else
InvalidFiles.Add(fileInfo)
End If
Next