excelvba

Generate a string of combined words without duplicates


I have a table with some delicious fruits :) But a fruit can occurre for several times in that table, for example:

Fruit y
Apple 1
Banana 2
Banana 3
Strawberry 4

In the final this table can have different fruits with up to 10 rows, so y can have a value from 1 to 10. What I'm struggeling with now, is generating a string in that format:

Apple + Banana x2 + Strawberry

So I want a string with each fruit for only one time. When the fruit occurs more than one time, I want "xAmount" beside the fruit. But with my code, it generates this string:

Apple + Banana x2 + Banana + Strawberry

Depending on the positions of the fruit and the amount of duplicates, the string I need will not be generated...

This is my code:

Dim y As Integer    
Dim Counter1 As Integer
Dim Counter2 As Integer
Dim NewBufferCounter As Integer
Dim a As Integer
Dim ArrayBuffer1(15) As String
Dim NewBuffer(15) As String
Dim FinalString(15) As String
Counter1 = 0
Counter2 = 0
a = 1

'2 nested FOR-Loops to compare the fruits for duplicates
For Counter1 = 0 To (y - 1)
        a = 1
                                     
        For Counter2 = Counter1 + 1 To (y - 1)
                    
                    If (ArrayBuffer1(Counter1) = ArrayBuffer1(Counter2)) And (ArrayBuffer1(Counter1) <> "") And (Counter1 <> Counter2) Then
                    a = a + 1
                    NewBuffer(NewBufferCounter) = ArrayBuffer1(Counter1) & " x" & a                 
                    
                    ElseIf (a = 1) And (ArrayBuffer1(Counter1) <> "") Then
                    NewBuffer(NewBufferCounter) = ArrayBuffer1(Counter1)
                    
                    Else
                    'Do nothing
                    End If
                    
                    If Counter2 = (y - 1) Then
                    NewBufferCounter = NewBufferCounter + 1
                    Else
                    'Do nothing
                    End If
                    
          Next Counter2
                
Next Counter1

'Further IF-Statement because the second FOR-Loop will skipped when "y" equals "1"           
If y = 1 Then
NewBuffer(NewBufferCounter) = ArrayBuffer1(0)
End If


AmountDiffFruits = NewBufferCounter



'Generate the final string I need
  For NewBufferCounter = 0 To AmountDiffFruits
               If (NewBuffer(NewBufferCounter) <> "") Then
                            If (IsEmpty(FinalString(NewBufferCounter))) Then
                            FinalString(0) = NewBuffer(NewBufferCounter)
                            
                            Else
                            FinalString(0) = FinalString(0) & " + " & NewBuffer(NewBufferCounter)
                        
                            End If
              Else
              'Do nothing
              End If
                   
     Next NewBufferCounter
                                    
Erase ArrayBuffer1()
Erase NewBuffer()
Erase FinalString()
NewBufferCounter = 0

Hope anybody has a solution for that... Thank you!


Solution

  • I think this is an excellent case for a Dictionary. A Dictionary is a structure that contains key-value pairs.

    The following code will read the list of fruits into a dictionary. It uses the fruit name as key and the counter as value. If it finds a fruit that is already in the dictionary, it increments the counter, else it will add the fruit as new entry into the dictionary and set the counter to 1.

    After creating the dictionary, we loop over all keys (=fruits) and build an array of string. If a fruit appeared more than once, it will get the suffix nX (with n being the number how often that fruit appeared).

    Finally we use the Join-function to create a string out of it.

    Sub ListFruits()
        Dim r As Range, row As Long
        Dim fruitDict As New Dictionary
        Set r = ActiveSheet.Range("A1").CurrentRegion
        For row = 2 To r.Rows.Count
            Dim fruit
            fruit = r.Cells(row, 1)
            If fruitDict.Exists(fruit) Then
                fruitDict(fruit) = fruitDict(fruit) + 1
            Else
                fruitDict.Add fruit, 1
            End If
        Next
        
        ReDim fruitArr(1 To fruitDict.Count) As String
        Dim i As Long
        For Each fruit In fruitDict.Keys
            Dim repeatCount As Long
            repeatCount = fruitDict(fruit)
            i = i + 1
            fruitArr(i) = fruit & IIf(repeatCount <= 1, "", " " & repeatCount & "x")
        Next
        
        Dim myFruitList As String
        myFruitList = Join(fruitArr, " + ")
        Debug.Print myFruitList
    End Sub
    

    Note that the Dictionary is not part of the VBA language. As I am a big fan of Early Binding, you will need to add a reference to the Microsoft Scripting.Runtime. Or you use Late Binding and change the definition from fruitDict to:

    Dim fruitDict As Object
    Set fruitDict = CreateObject("Scripting.Dictionary")