我已经在这个问题的@ Artur Udod 回答中采用了排列生成器解决方案:
Print all the possible combinations of "X" amount of characters with "X" string length (Brute Force)
我已经修改了代码以返回字符串而不是Char
的集合,并且还能够指定是否允许字符重复生成的排列:
Public Shared Function PermuteCharacters(ByVal charSet As IEnumerable(Of Char),
ByVal length As Integer,
ByVal isRepetitionAllowed As Boolean) As IEnumerable(Of String)
If length = 1 Then
Return charSet.Select(Function(c As Char)
Return New String(New Char() {c})
End Function)
Else
Return PermuteCharacters(charSet, length - 1, isRepetitionAllowed).
SelectMany(Function(x As String) charSet,
Function(str As String, c As Char)
Select Case isRepetitionAllowed
Case True
Return str & c
Case Else
' Firstly I need to check if string is empty because
' String.Contains() will throw an exception on empty strings.
' This need to be fixed to avoid empty strings.
If String.IsNullOrEmpty(str) Then
Return Nothing
End If
If Not str.Contains(c) Then
Return str & c
Else
Return Nothing
End If
End Select
End Function)
End If
End Function
示例用法:
Dim permutations As IEnumerable(Of String) =
PermuteCharacters("123456789", 2, isRepetitionAllowed:=False)
问题是当我将重复设置为 False 时,该函数将创建,解析和返回空字符串,其中性能的负点将导致大的设置或置换长度。
我知道我可以使用IEnumerable.Distinct()
方法删除所有空字符串但只有一个,但这会再次迭代整个大集合,从而导致代码本身产生更多负面影响。
如何有效地设计功能,计算性能,创建排列集所需的总执行时间?
重要的是要说我没有看到 LINQ 的使用是性能的一个非常不利的因素,我将继续使用 LINQ 因为它允许开发一个减少代码,而不是通用循环所需的数千行,以便像这样翻译 LINQ 查询。
PS:我的第二个目标是在函数上实现Iterator
关键字,以提高其性能,如果有人可以通过解决此问题的解决方案来实现Iterator
功能将会更多比真棒(和完美)。
答案 0 :(得分:1)
我不认为你应该从linq开始,因为它看起来并不像你掌握了它。也许尝试一个更简单的结构:
Private Shared Iterator Function BuildCombination(distinctChars As IEnumerable(Of Char), usedChars As Stack(Of Char), length As Integer, everyCharIsDistinct As Boolean) As IEnumerable(Of String)
' we give the method everything it needs to work
Dim availableChars As IEnumerable(Of Char) = distinctChars
' what chars are available
If everyCharIsDistinct Then
availableChars = availableChars.Where(Function(c As Char) Not usedChars.Contains(c))
End If
' if the string to return is of length 1, every available char can be returned directly
If length = 1 Then
For Each availableChar As Char In availableChars
Yield New String(New Char()() = { availableChar })
Next
Else
' else we add each available char to the used list and we recurse to concat it with every possible substring
For Each availableChar As Char In availableChars
usedChars.Push(availableChar)
For Each possibleSubstring As String In Program.BuildCombination(distinctChars, usedChars, length - 1, everyCharIsDistinct)
Yield New String(New Char()() = { availableChar }) + possibleSubstring
Next
usedChars.Pop()
Next
End If
Return
End Function
使用此包装器调用它,我们设置列表以及检查健全参数的位置:
Private Shared Sub FindCombinations(possibleChars As String, length As Integer, everyCharIsDistinct As Boolean)
If possibleChars.Length = 0 Then
Throw New InvalidOperationException()
End If
If everyCharIsDistinct AndAlso possibleChars.Length < length Then
Throw New InvalidOperationException()
End If
Dim distinctChars As IEnumerable(Of Char) = possibleChars.Distinct(Of Char)()
Dim listOfUsedChars As Stack(Of Char) = New Stack(Of Char)()
For Each s As String In Program.BuildCombination(distinctChars, listOfUsedChars, length, everyCharIsDistinct).ToList(Of String)()
Console.WriteLine(s)
Next
End Sub