1

我有这个“结果”变量,它是一种IEnumerable类型:

Dim result = GetCombinations(TextBox1.Text, StringLength)

要获取/写入变量的内容,我需要使用 For 迭代其中的所有项目,然后将每个项目转换为数组,如下所示:

    For Each item In result
        RichTextBox1.Text += vbNewLine & item.ToArray
        Application.DoEvents()
    Next

...所以我的回答是,如果我可以改进我的代码,例如加入 IEnumerable 内容来做类似的事情:

 RichTextBox1.Text = String.Join(vbNewLine, result) ' This does not work.

我的意思是,“一次性”的事情。

如果不是,还有比 For 更好(更快)的替代方案吗?

更新

这是完整的代码:

Private Shared Function GetCombinations(Of T)(list As IEnumerable(Of T), length As Integer) As IEnumerable(Of IEnumerable(Of T))

    If length = 1 Then
        Return list.[Select](Function(x) New T() {x})
    Else
        Return GetCombinations(list, length - 1).SelectMany(Function(x) list, Function(t1, t2) t1.Concat(New T() {t2}))
    End If

End Function

   Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    RichTextBox1.Clear()

    Dim result = GetCombinations("abc", 5)

    ' Dim result2 As IEnumerable(Of String) = result.Select(Function(item) New String(item))

    ' RichTextBox1.Text = String.Join(vbNewLine, result)

    For Each item In result
        RichTextBox1.Text &= vbNewLine & item.ToArray
        '  Application.DoEvents()
    Next

End Sub

更新 2

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    ' Method result
    Dim result As IEnumerable = Permute_Characters("abc", 2)

    ' Combine strings into lines
    ' Dont work
    RichTextBox1.Text = String.Join(Environment.NewLine, result.ToString.ToArray)

End Sub
4

3 回答 3

2

每次更新 RichTextBox.Text 属性时,您可能会产生开销,因为它会执行自己的内部逻辑。另外,您首先要读取该值,因此那里的开销会增加一倍。

相反,我会在循环中使用 StringBuilder。您可以使用 StringBuilder 的 Append 方法重载将字符添加到其中。这个重载接受一个字符数组。

最后,一旦您的 StringBuilder 构建完成,您就可以调用 RichTextBox1.Text = mystringbuilder.ToString()。

这样,您将避免调用富文本框的“清除”方法以及为每一行读取和重新分配它的文本属性。您还将避免在执行字符串连接操作时在内存中创建过多的字符串副本。

编辑每条评论:要在没有循环的情况下在一行中执行此操作,您可以使用 LINQ 扩展函数Aggregate。我使用 C#,但您可以为此使用 VB 语法。

var v = GetCombinations(...);
RichTextBox1.Text = v.Aggregate((str, p) => str + Environment.NewLine + p);

但这仍然会进行字符串连接,所以我仍然建议使用 StringBuilder。

于 2013-06-06T15:29:29.070 回答
1

更新问题的更新答案:

此代码按预期工作(我能推测的最好的)

Private Function GetCombinations(ByVal list As Char(), ByVal length As Integer) As Char()()
    If length = 1 Then
        Return list.[Select](Function(x) (New Char() {x})).ToArray()
    Else
        Return GetCombinations(list, length - 1).SelectMany(Function(x) list, Function(t1, t2) t1.Concat(New Char() {t2}).ToArray()).ToArray()
    End If
End Function

Sub Main()
    Dim result = GetCombinations("abc".ToCharArray(), 3)
    Dim list = result.Select(Function(x) New String(x)).ToArray()
    Debug.WriteLine(String.Join(Environment.NewLine, list))
End Sub

结果:

aaa
aab
aac
aba
abb
abc
aca
acb
acc
baa
bab
bac
bba
bbb
bbc
bca
bcb
bcc
caa
cab
cac
cba
cbb
cbc
cca
ccb
ccc

它可能不是最有效的,但它是一个开始,因为 OP 代码不起作用。它取决于将锯齿状的字符数组转换为字符串数组。使用 . 将每一行从 char 数组转换为字符串New String(x)

于 2013-06-06T14:37:42.670 回答
1

如果您想要速度并减少内存占用,请减少递归和对 LINQ 的调用(隐藏内部循环)。

现在我明白了你想要什么,试试这个代码

Public Function GetCombinations(ByVal letters As String, ByVal word_length As Integer) As String()
    ' abc,2 -> aa, ab, ac, ba, bb, bc, ca, cb, cc
    ' abc,3 -> aaa, aab, aac, aba, abb, abc, .. , caa, cab, cac
    Dim list = letters.ToCharArray()
    Dim N_letters = list.Length
    Dim N_combinations = CLng(Math.Pow(N_letters, word_length))
    Dim result As New List(Of String)(N_combinations)
    ' indeces holds which letter to use for each combination
    ' 0 = a, 1 = b, 2 = c, ...
    ' it starts with (0,0,0..) which corresponds to "aaa.."
    Dim indeces As Integer() = New Integer(word_length-1) {}
    'Default to 0's
    Dim k As Integer
    Do
        ' convert indeces into combination, example: (1,0,2) => (b,a,c) => "bac"
        result.Add(New String(indeces.Select(Function(x) list(x)).ToArray()))
        'Find next combination by incrementing the first letter,
        'and if it spills-over, reset it to 'a' and try the next letter in the word
        k = 0
        Do
            indeces(k) += 1

            If indeces(k) = N_letters Then
                indeces(k) = 0
                k = k + 1
            Else
                Exit Do
            End If
        Loop While k < word_length
    Loop While k < word_length

    Return result.ToArray()

End Function


Sub Main()
    Dim result = GetCombinations("abc", 5)
    Debug.WriteLine(String.Join(ControlChars.CrLf, result))
End Sub

结果

aaaaa
baaaa
caaaa
abaaa
bbaaa
cbaaa
acaaa
bcaaa
ccaaa
aabaa
babaa
...
caccc
abccc
bbccc
cbccc
acccc
bcccc
ccccc
于 2013-06-07T15:46:45.577 回答