Reputation: 20464
I'm trying to write a word combination generator, I mean to print all the possible combinations of "X" amount of characters with "X" string length,
First of all I need to say I saw a question in StackOverFlow about exactly this problem which have a lot of answers of word generators to do exaclty this (on different languages), but please, don't mark this as duplicate or don't comment my question only to reference-me that link 'cause I've tested ALL the C# and VBNET codes of that question and really none works 100% as expected, see the combinations I need:
For example, If I have "a","b" and "c" characters, and I want to make all combinations of those characters in a string of "3" length then this is the result I expect:
' Expected result, 27 combinations:
'
' 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
(The sort don't matter, I can sort it later.)
...But so far of that expected result this is what I could get:
'a
'aa
'aaa
'b
'bb
'bbb
'c
'cc
'ccc
I have done this time ago in two languages (Ruby and Batch) but using nested Fors (A lot of Fors together each For appending only one letter to the other For output), of course If I'm trying to do this in VBNET is to avoid the suing of a lot of Fors, and to do it in a better performance way.
In the code below you can see how I try to allocate all the combinations at RAM memory (an array) instead of writing they to the physical disk, so I want to write this code using a logic method and in a better performance way, then I want to save all the combinations "in the memory" first and thats the reason too why I don't want to use a lot of fors (the performance).
This was my last try, all is explained in comment-lines:
Public Class Form1
Dim characters As Char() ' Default value: {"a","b","c"}
Dim StringLength As Int64 ' Default value: 3
Dim TotalCombinations As Int64 ' Default value: 27
Dim strarray(99999999) As String ' Default size: "99.999.999" million of combinations in memory (I need to confirm this from an expert).
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim index As Int64 = 0
For column As Int64 = 0 To TotalCombinations - 1 ' For 0 to 26
For Each character As Char In characters ' Characters = {"a","b","c"}
If column < index Then
index = 0 ' I reset index value 'cause... just experimenting things.
Try
strarray(index) += characters(index)
RichTextBox1.Text += strarray(index) & ControlChars.NewLine
Catch
End Try
Else
Try
strarray(index) += characters(index)
RichTextBox1.Text += strarray(index) & ControlChars.NewLine
Catch
End Try
End If
Next
index += 1
Next
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
characters = sender.text.ToCharArray ' Result: {"a","b","c"}
Calculate_Combinations() ' Result: 27
End Sub
Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
StringLength = sender.value ' Result: 3
Calculate_Combinations() ' Result: 27
End Sub
Private Sub Calculate_Combinations()
Try
TotalCombinations = ((characters.LongLength * StringLength) * StringLength) ' Result: 27
Label1.Text = ((characters.LongLength * StringLength) * StringLength) & " number of combinations." ' Result: 27
Catch : End Try
End Sub
End Class
I precise help.
Upvotes: 2
Views: 2696
Reputation: 4743
A wonderful solution using Linq by @pengyang that works with IEnumerables:
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})
End If
Return GetCombinations(list, length - 1).SelectMany(Function(x) list, Function(t1, t2) t1.Concat(New T() {t2}))
End Function
Then:
Dim result = GetCombinations("abc", 3)
Screenshot from LinqPad: https://i.sstatic.net/JAHdN.png
Upvotes: 2
Reputation: 11773
Three nested loops
Dim foo As String = "abc"
For Each c1 As Char In foo
For Each c2 As Char In foo
For Each c3 As Char In foo
Debug.WriteLine(String.Join("", c1, c2, c3))
Next
Next
Next
Upvotes: 0