Jump to content

Execute items in for-next loop in random order


 Share

Go to solution Solved by water,

Recommended Posts

Hello everyone

Suppose I have a for-next loop like this:

 

For $i = 1 to 9
; Do something that involves $i
Next
But I don't want $i to go from 1 to 9 in numerical order, but instead I want $i to use the range 1 to 9 randomly (or semi-randomly), and use every number only once, how would I do that?

In other words, instead of letting $i be this:

1 then 2 then 3 then 4 then 5 etc

I want it $i to be e.g. this:

2 then 5 then 7 then 9 then 4 etc

using each of the items 1 to 9 only once.

It doesn't have to be a for-next loop if there is a better way of doing it. The application of this is to read a file with e.g. 9 lines in it, in which I do something with each of the lines (one line at a time) in random order.

If you could just point me in the right direction, please...

Thanks

Samuel

Added: Oh, in this example I used "1 to 9" but the actual file I'm going to process will have about 10 000 lines.

Edited by leuce
Link to comment
Share on other sites

  • Moderators

leuce,

I would create an array holding 1-9 and then shuffle it - looping from 1 to 9 now will produce those values in a random order. :)

Here is an example using the _ArrayShuffle function that will be in the next AutoIt release: ;)

#include <Array.au3>

Global $aArray[10]

For $i = 1 To 9
    $aArray[$i] = $i
Next

_ArrayDisplay($aArray, "Default", Default, 8)

_ArrayShuffle($aArray, 1, 0)

_ArrayDisplay($aArray, "Shuffled", Default, 8)

Func _ArrayShuffle(ByRef $avArray, $iStart_Row = 0, $iEnd_Row = 0, $iCol = 0)

    ; Fisher–Yates algorithm

    If $iStart_Row = Default Then $iStart_Row = 0
    If $iEnd_Row = Default Then $iEnd_Row = 0
    If $iCol = Default Then $iCol = 0

    If Not IsArray($avArray) Then Return SetError(1, 0, -1)
    Local $iDim_1 = UBound($avArray, $UBOUND_ROWS)
    If $iEnd_Row = 0 Then $iEnd_Row = $iDim_1 - 1
    If $iStart_Row < 0 Or $iStart_Row > $iDim_1 - 1 Then Return SetError(3, 0, -1)
    If $iEnd_Row < 1 Or $iEnd_Row > $iDim_1 - 1 Then Return SetError(3, 0, -1)
    If $iStart_Row > $iEnd_Row Then Return SetError(4, 0, -1)

    Local $vTmp, $iRand
    Switch UBound($avArray, $UBOUND_DIMENSIONS)
        Case 1
            For $i = $iEnd_Row To $iStart_Row + 1 Step -1
                $iRand = Random($iStart_Row, $i, 1)
                $vTmp = $avArray[$i]
                $avArray[$i] = $avArray[$iRand]
                $avArray[$iRand] = $vTmp
            Next
            Return 1
        Case 2
            Local $iDim_2 = UBound($avArray, $UBOUND_COLUMNS)
            If $iCol < 0 Or $iCol > $iDim_2 - 1 Then Return SetError(5, 0, -1)
            Local $iCol_Start, $iCol_End
            If $iCol Then
                $iCol_Start = $iCol
                $iCol_End = $iCol
            Else
                $iCol_Start = 0
                $iCol_End = $iDim_2 - 1
            EndIf
            For $i = $iEnd_Row To $iStart_Row + 1 Step -1
                $iRand = Random($iStart_Row, $i, 1)
                For $j = $iCol_Start To $iCol_End
                    $vTmp = $avArray[$i][$j]
                    $avArray[$i][$j] = $avArray[$iRand][$j]
                    $avArray[$iRand][$j] = $vTmp
                Next
            Next
            Return 1
        Case Else
            Return SetError(2, 0, -1)
    EndSwitch

EndFunc   ;==>_ArrayShuffle
That should do the trick for you. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • Solution

Let's say you read the file into an array and mark all processed entries ("****" in this example):

Global $aArray[1], $iItem, $iProcessed = 0, $sFilename = "Your input file"
FileReadToArray($sFilename, $aArray)
While 1
    $iItem = Random(1, $aArray[0], 1) 
    If $aArray[$iItem] <> "****" Then
        ; insert code to process this record here !!
        $aArray[$iItem] = "****" ; Mark as processed
        $iProcessed = $iProcessed + 1
        If $iProcessed = $aArray[0] Then ExitLoop
    EndIf
WEnd
Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

The problem with Water's answer is that you may keep hitting the same element. With a large array you will be in trouble. The solution is to shuffle the array elements first and then run through them one by one.

.

; ====================================================================================================================
; Name...........: _ArrayShuffle
; Description ...: Shuffles the elements within a one dimensional array.
; Syntax.........: _ArrayShuffle(ByRef $avArray)
; Parameters ....: $avArray - [ByRef] The array to shuffle
; Return values .: Success   - Returns 1
;                  Failure   - Returns zero and sets @error to the following values:
;                  |@error = 1 : $avArray is not a one dimensional array
; Author ........: jchd
; Modified.......: czardas
; Related .......: _MultiDimShuffle
; Link ..........:
; Example .......:
; ===============================================================================================================================

Func _ArrayShuffle(ByRef $avArray)
    If Not IsArray($avArray) Or UBound($avArray, 0) > 1 Then Return SetError (1)
    Local $vTemp, $r, $iBound = UBound($avArray) -1
    For $i = 0 To $iBound
        $r = Random(0, $iBound, 1)
        $vTemp = $avArray[$i]
        $avArray[$i] = $avArray[$r]
        $avArray[$r] = $vTemp
    Next
    Return 1
EndFunc ;==> _ArrayShuffle

;

Oh, I just noticed M23 also suggested this approach.

Edited by czardas
Link to comment
Share on other sites

I just checked and it only takes 0.2 seconds to process 10000 records. I feared to be worse ;)

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

There should be a variable processing time ranging from very quick to very very slow - depending on how reliable Random() is. I imagine the longest possible duration to be years, or if Random() is really good, then it could possibly take millenia - theoretically speaking. Keep rolling a dice and always landing on 6 is unlikely though.

Edited by czardas
Link to comment
Share on other sites

I have run my code 1000 times in a loop and the max. processing time was 0.438 seconds. Seems Random returns real random numbers ;)

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...