Randomly change the value containing data in the array

MyHanhCB

New Member
Joined
Feb 20, 2023
Messages
30
Office Version
  1. 2016
Platform
  1. Windows
Hello everyone in the forum.
I have the following code that randomly changes the value contained in an array. But I think it's still not optimized.
Looking forward to more optimal solutions from professional programmers to consult and learn more about vba excel. Thank you very much.
VBA Code:
Function ShuffleArray(arr As Variant) As Variant
Dim j%, i%, randomIndex%, dict As New Dictionary, myarr As Variant
         Randomize
        ReDim myarr(1 To UBound(arr, 1), 1 To UBound(arr, 2))
            For j = LBound(arr, 1) To UBound(arr, 1)
            randomIndex = Int((UBound(arr, 1) - LBound(arr, 1) + 1) * Rnd + LBound(arr, 1))
        If Not dict.Exists(randomIndex) Then
                   dict.Add randomIndex, randomIndex
tiepRndIx:
    For i = LBound(arr, 2) To UBound(arr, 2)
        myarr(j, i) = arr(randomIndex, i)
    Next i
        Else
tiepRndIx1:
            randomIndex = Int((UBound(arr, 1) - LBound(arr, 1) + 1) * Rnd + LBound(arr, 1))
            If Not dict.Exists(randomIndex) Then
            dict.Add randomIndex, randomIndex
            GoTo tiepRndIx
            Else
            GoTo tiepRndIx1
            End If
         End If
            Next j
ShuffleArray = myarr
End Function
 

Excel Facts

Select a hidden cell
Somehide hide payroll data in column G? Press F5. Type G1. Enter. Look in formula bar while you arrow down through G.
The first thing that jumps out at me is your indentation - it makes it very difficult to follow.
The second thing that jumps out me is that you've used GoTo, which you really should avoid, especially here where you are GoToing a part of a conditional statement. But this then reveals that you seem to be writing the same code twice.
So there a number of optimisations you can make to this, but I think it would help you if you could set out (maybe in pseudocode) what the logic of the code is - because at present, it's a bit muddled.
 
Upvote 0
This procedure sorts each column of the array in turn, independantly of the other columns, and based upon a unique
randomly generated decimal which has the effect of changing each value for that of another.

It creates a temporary worksheet to do this it which it then deletes at the end.

VBA Code:
Public Function fncShuffleArray(arr() As Variant) As Variant
Dim rngColumn As Range
Dim Ws As Worksheet

    Set Ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
    
    Ws.Name = Format(Now(), "ddmmyyyy") & Format(Now(), "hhmmss")
    
    Ws.Range("A1").Resize(UBound(arr, 1), UBound(arr, 2)).Value = arr
        
    For Each rngColumn In Ws.Range("A1").CurrentRegion.Columns
        rngColumn.Offset(0, 1).EntireColumn.Insert
        rngColumn.Offset(0, 1).Formula = "=RAND()"
        rngColumn.Offset(0, 1).Value = rngColumn.Offset(0, 1).Value
        Ws.Sort.SortFields.Clear
        Ws.Sort.SortFields.Add rngColumn.Offset(0, 1), xlSortOnValues, xlAscending
        With Ws.Sort
            .SetRange rngColumn.Resize(rngColumn.Rows.Count, 2)
            .Apply
        End With
        rngColumn.Offset(0, 1).EntireColumn.Delete
    Next rngColumn

    arr = Ws.Range("A1").CurrentRegion
    
    Application.DisplayAlerts = False
    Ws.Delete
    Application.DisplayAlerts = True
    
    fncRandomOrderColumns = arr

End Function
 
Upvote 0
Another option
VBA Code:
Function ShuffleArray(arr As Variant) As Variant
   Dim j As Long, i As Long, randomIndex As Long
   Dim dict As Object
   Dim myarr As Variant
   
   Set dict = CreateObject("scripting.dictionary")
   ReDim myarr(1 To UBound(arr, 1), 1 To UBound(arr, 2))
   Randomize
   
   For j = LBound(arr, 1) To UBound(arr, 1)
      randomIndex = Int((UBound(arr, 1) - LBound(arr, 1) + 1) * Rnd + LBound(arr, 1))
      Do While dict.Exists(randomIndex)
         randomIndex = Int((UBound(arr, 1) - LBound(arr, 1) + 1) * Rnd + LBound(arr, 1))
      Loop
      dict.Add randomIndex, Nothing
      For i = LBound(arr, 2) To UBound(arr, 2)
         myarr(j, i) = arr(randomIndex, i)
      Next i
   Next j
   ShuffleArray = myarr
End Function
 
Upvote 0
Solution
The first thing that jumps out at me is your indentation - it makes it very difficult to follow.
The second thing that jumps out me is that you've used GoTo, which you really should avoid, especially here where you are GoToing a part of a conditional statement. But this then reveals that you seem to be writing the same code twice.
So there a number of optimisations you can make to this, but I think it would help you if you could set out (maybe in pseudocode) what the logic of the code is - because at present, it's a bit muddled.
yes, thanks for the comment.
 
Upvote 0
This procedure sorts each column of the array in turn, independantly of the other columns, and based upon a unique
randomly generated decimal which has the effect of changing each value for that of another.

It creates a temporary worksheet to do this it which it then deletes at the end.

VBA Code:
Public Function fncShuffleArray(arr() As Variant) As Variant
Dim rngColumn As Range
Dim Ws As Worksheet

    Set Ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
   
    Ws.Name = Format(Now(), "ddmmyyyy") & Format(Now(), "hhmmss")
   
    Ws.Range("A1").Resize(UBound(arr, 1), UBound(arr, 2)).Value = arr
       
    For Each rngColumn In Ws.Range("A1").CurrentRegion.Columns
        rngColumn.Offset(0, 1).EntireColumn.Insert
        rngColumn.Offset(0, 1).Formula = "=RAND()"
        rngColumn.Offset(0, 1).Value = rngColumn.Offset(0, 1).Value
        Ws.Sort.SortFields.Clear
        Ws.Sort.SortFields.Add rngColumn.Offset(0, 1), xlSortOnValues, xlAscending
        With Ws.Sort
            .SetRange rngColumn.Resize(rngColumn.Rows.Count, 2)
            .Apply
        End With
        rngColumn.Offset(0, 1).EntireColumn.Delete
    Next rngColumn

    arr = Ws.Range("A1").CurrentRegion
   
    Application.DisplayAlerts = False
    Ws.Delete
    Application.DisplayAlerts = True
   
    fncRandomOrderColumns = arr

End Function
yes, thanks for the suggestion.
 
Upvote 0
Another option
VBA Code:
Function ShuffleArray(arr As Variant) As Variant
   Dim j As Long, i As Long, randomIndex As Long
   Dim dict As Object
   Dim myarr As Variant
  
   Set dict = CreateObject("scripting.dictionary")
   ReDim myarr(1 To UBound(arr, 1), 1 To UBound(arr, 2))
   Randomize
  
   For j = LBound(arr, 1) To UBound(arr, 1)
      randomIndex = Int((UBound(arr, 1) - LBound(arr, 1) + 1) * Rnd + LBound(arr, 1))
      Do While dict.Exists(randomIndex)
         randomIndex = Int((UBound(arr, 1) - LBound(arr, 1) + 1) * Rnd + LBound(arr, 1))
      Loop
      dict.Add randomIndex, Nothing
      For i = LBound(arr, 2) To UBound(arr, 2)
         myarr(j, i) = arr(randomIndex, i)
      Next i
   Next j
   ShuffleArray = myarr
End Function
yes, thanks for the solution.
 
Upvote 0
Glad we could help & thanks for the feedback.
 
Upvote 0

Forum statistics

Threads
1,215,165
Messages
6,123,390
Members
449,098
Latest member
ArturS75

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top