List(Of ClassA) 包含一个 List(of ClassB),其中包含一个字符串。检查新字符串是否已经存在
List(Of ClassA) contains a List(of ClassB) and in it a string. Check if the new string already exists
我有一个列表(A 类),其中包含一个列表(B 类)。这包含一个名为“heading”的字符串。
我使用文本框读入了一个新字符串。我想检查新字符串是否已经存在。
我以前的代码有效,但我认为可以用更优雅的方式来完成。我发现它有点困难,因为我有这个 class 结构。我为您创建了一个新项目,并且只复制了必要但可重现的源代码。
Form1.vb
Imports Microsoft.VisualBasic.ControlChars
Public NotInheritable Class FormMain
Private allA As New List(Of ClassA)
Private the_new_String As String = ""
Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
allA.Add(New ClassA)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 0 To allA.Count - 1 Step 1
For j As Integer = 0 To allA(i).allB.Count - 1 Step 1
If allA(i).allB(j).Heading = the_new_String Then
MessageBox.Show($"Diesen Titel gibt es bereits.{NewLine}This title already exists.",
"",
MessageBoxButtons.OK,
MessageBoxIcon.Information)
Return
End If
Next
Next
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
the_new_String = TextBox1.Text
End Sub
End Class
ClassA.vb
Public Class ClassA
Public allB As New List(Of ClassB)
Public Sub New()
allB.Add(New ClassB())
End Sub
End Class
ClassB.vb
Public Class ClassB
Public Heading As String = "Test"
End Class
If allA.Any(Function(a) a.allB.Any(Function(b) b.Heading = the_new_String)) Then
'The specified text already exists.
End If
你的嵌套循环没有问题。您所做的任何其他操作最终都会编译成相同的嵌套循环(尽管循环语句可能隐藏在 Linq 函数调用中)。例如,在发布的另一个答案中,每个 Any
调用都隐藏了一个循环。
作为另一种选择,您可以考虑使用 SelectMany
,这是用于展平层次结构的 Linq 例程。
结果是,
If allA.SelectMany(Function(a) a.allB.Select(Function(b) b.Heading)) _
.Any(Function(heading) heading = testString) Then
'Proposed heading already exists
End If
我相信这最终会以与您的原始代码或其他答案中的代码相似的算法效率结束。 SelectMany
、Select
和 Any
都应该使用延迟执行,所以我认为只要找到匹配项,它就会在没有额外迭代的情况下跳出隐式嵌套循环。 (很容易推断出 Linq 将为您提供的集合操作,但识别隐藏在语句后面的循环复杂性并不一定容易,尤其是当某些 Linq 函数会急切求值而其他函数会延迟时。)
我有一个列表(A 类),其中包含一个列表(B 类)。这包含一个名为“heading”的字符串。 我使用文本框读入了一个新字符串。我想检查新字符串是否已经存在。
我以前的代码有效,但我认为可以用更优雅的方式来完成。我发现它有点困难,因为我有这个 class 结构。我为您创建了一个新项目,并且只复制了必要但可重现的源代码。
Form1.vb
Imports Microsoft.VisualBasic.ControlChars
Public NotInheritable Class FormMain
Private allA As New List(Of ClassA)
Private the_new_String As String = ""
Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
allA.Add(New ClassA)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 0 To allA.Count - 1 Step 1
For j As Integer = 0 To allA(i).allB.Count - 1 Step 1
If allA(i).allB(j).Heading = the_new_String Then
MessageBox.Show($"Diesen Titel gibt es bereits.{NewLine}This title already exists.",
"",
MessageBoxButtons.OK,
MessageBoxIcon.Information)
Return
End If
Next
Next
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
the_new_String = TextBox1.Text
End Sub
End Class
ClassA.vb
Public Class ClassA
Public allB As New List(Of ClassB)
Public Sub New()
allB.Add(New ClassB())
End Sub
End Class
ClassB.vb
Public Class ClassB
Public Heading As String = "Test"
End Class
If allA.Any(Function(a) a.allB.Any(Function(b) b.Heading = the_new_String)) Then
'The specified text already exists.
End If
你的嵌套循环没有问题。您所做的任何其他操作最终都会编译成相同的嵌套循环(尽管循环语句可能隐藏在 Linq 函数调用中)。例如,在发布的另一个答案中,每个 Any
调用都隐藏了一个循环。
作为另一种选择,您可以考虑使用 SelectMany
,这是用于展平层次结构的 Linq 例程。
结果是,
If allA.SelectMany(Function(a) a.allB.Select(Function(b) b.Heading)) _
.Any(Function(heading) heading = testString) Then
'Proposed heading already exists
End If
我相信这最终会以与您的原始代码或其他答案中的代码相似的算法效率结束。 SelectMany
、Select
和 Any
都应该使用延迟执行,所以我认为只要找到匹配项,它就会在没有额外迭代的情况下跳出隐式嵌套循环。 (很容易推断出 Linq 将为您提供的集合操作,但识别隐藏在语句后面的循环复杂性并不一定容易,尤其是当某些 Linq 函数会急切求值而其他函数会延迟时。)