Jump to content

[SOLVED] Random Assignment Question


Recommended Posts

Hi,

I know this should be easy for most members here, but I can't figure it how :)

I have first array, let say the content is a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, z, y and z.

I have another array, let say the content is 1, 2, 3, 4, 5

I want to assigned the content of first array randomly to each of second array, so each of second array will get arround 5 entry, and some will get 6. All of the content of first array should distributed to second array.

For example:

1 will get c, n, t, u, v

2 will get a, d, h, r, s

3 will get d, p, v, y, z

etc

Thanks a lot and hope somebody understand what I'm trying to say and can help me with the logic/sample code :)

Edited by michaelslamet
Link to comment
Share on other sites

I was thinking something like this:

#include <array.au3>
Global $iDestCount = 5 ; the amount of elements you want to distribute the letters over.
Global $aSource = StringSplit("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,z,y,z",",") ; the array of letters (source)
Global $aDest[$iDestCount] ;the destination.

_ArrayRandom($aSource,1) ;This way all letters will be used exactly once.

While 1
    For $i = 0 To $iDestCount -1
        $aDest[$i] &= $aSource[$aSource[0]]
        If $aSource[0] = 1 Then ExitLoop 2 ;exit when all letters are distributed
        If $aSource[0] > $iDestCount Then $aDest[$i] &= "," ;add a delimiter if another letter is expected.
        $aSource[0] -= 1
    Next
WEnd

_ArrayDisplay($aDest,"Distributed letters over " & $iDestCount & " elements")


; #FUNCTION# ====================================================================================================================
; Name...........: _ArrayRandom
; Description ...: Randomize the row order of (part of) a 1D or 2D array.
; Syntax.........: _ArrayRandom(ByRef $avArray, $iStart = 0, $iEnd = 0)
; Parameters ....: $avArray     - Array to randomize
;               $iStart     - [optional] Index of array to start at
;               $iEnd       - [optional] Index of array to stop at
; Return values .: Success - 1
;               Failure - 0, sets @error:
;               |1 - $avArray is not an array
;               |2 - $iStart is greater than $iEnd
; Author ........: Tom Vernooij
; Modified.......:
; Remarks .......: Based on Yashied's method
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _ArrayRandom(ByRef $avArray, $iStart=0, $iEnd=0)
    If Not IsArray($avArray) Then Return SetError(1,0,0)

    Local $iRow, $iCol, $rRow, $Temp, $numCols = UBound($avArray,2), $Ubound = UBound($avArray) -1

    ; Bounds checking
    If $iEnd < 1 Or $iEnd > $UBound Then $iEnd = $UBound
    If $iStart < 0 Then $iStart = 0
    If $iStart > $iEnd Then Return SetError(2, 0, 0)

    ;   for 2 dimentional arrays:
    If $numCols Then
        For $iRow = $iStart To $iEnd ;for each row...
            $rRow = Random($iStart, $iEnd, 1) ;...select a random row
            For $iCol = 0 To $numCols -1    ;swich the values for each cell in the rows
                $Temp = $avArray[$iRow][$iCol]
                $avArray[$iRow][$iCol] = $avArray[$rRow][$iCol]
                $avArray[$rRow][$iCol] = $Temp
            Next
        Next

    ;   for 1 dimentional arrays:
    Else
        For $iRow = $iStart To $iEnd ;for each cell...
            $rRow = Random($iStart, $iEnd, 1) ;...select a random cell
            $Temp = $avArray[$iRow] ;switch the values in the cells
            $avArray[$iRow] = $avArray[$rRow]
            $avArray[$rRow] = $Temp
        Next
    EndIf
    Return 1
EndFunc

With this script the longest strings will always be at the start of the array. (in this case $aDest[0] will always have 6 letters, all others will have 5). To have random elements contain the longer strings, just use _ArrayRandom on $aDest.

Link to comment
Share on other sites

Hi JoHanatCent,

The duplicate should removed.

Thanks for reply and help :)

"I have first array, let say the content is a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, z, y and z.

"

Got a little side trackt so I see there is a solution already (But not removing the duplicates)

Seeing that there was aduplicate in the OP's request I did a different approach.

.... if someone is interested!

#include <Array.au3>
Dim $Array2[6]
$start = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,a,z";If duplicate in this string then While will never end!!!
;So to get the duplicates out use _ArrayUnique
$start = StringSplit($start, ",")
_ArrayDelete($start, 0)
$start = _ArrayUnique($start);No Duplicates
Dim $RndAplh[$start[0] + 1]
$1 = 0
While $1 < $start[0]
    $rnd = Random(1, $start[0], 1)
    _ArraySearch($RndAplh, $start[$rnd]);No Duplicates
    If @error Then
        $1 += 1
        $RndAplh[$1] = $start[$rnd]
    EndIf
WEnd
$RndAplh[0] = $1
$1 = 1
While $1 < $start[0]
    For $2 = 1 To UBound($Array2) - 1
        $Array2[$2] = $RndAplh[$1] & "," & $Array2[$2]
        If $1 > $start[0] - UBound($Array2) Then $Array2[$2] = StringLeft($Array2[$2], StringLen($Array2[$2]) - 1)
        $1 += 1
    Next
WEnd
$Array2[0] = Int($1/(UBound($Array2) - 1))
_ArrayDisplay($Array2, "Unique")
Link to comment
Share on other sites

Hi Johan,

Tried your code just now.

It only distribute 25 of 26 unique content of them, 1 content is missing (not distributed).

Could you please help to check the code?

thanks a lot :)

I could. In the above script it started with 28 ($Start) and ended in 26 after getting rid of the duplicates.

Can you post the contents of your $Start that you used?

Link to comment
Share on other sites

Here is a fix for JoHanatCent's script: (problem was in the last While)

#include <Array.au3>
Dim $Array2[6]
$start = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,a,z";If duplicate in this string then While will never end!!!
;So to get the duplicates out use _ArrayUnique
$start = StringSplit($start, ",")
_ArrayDelete($start, 0)
$start = _ArrayUnique($start);No Duplicates
Dim $RndAplh[$start[0] + 1]
$1 = 0
While $1 < $start[0]
    $rnd = Random(1, $start[0], 1)
    _ArraySearch($RndAplh, $start[$rnd]);No Duplicates
    If @error Then
        $1 += 1
        $RndAplh[$1] = $start[$rnd]
    EndIf
WEnd
$RndAplh[0] = $1
$1 = 1
While  1 ;As the for loop increases $1 multiple times before returning here,  this is not a good place to check for a break contition based on the  value of $1
    For $2 = 1 To UBound($Array2) - 1
        $Array2[$2] &= $RndAplh[$1]
         If $1 <= $start[0] - (UBound($Array2)-1) Then $Array2[$2] &= ","  ;The fix caused problems with the original solution. (trimming letters  when it shouldn't)
        $1 += 1
        If $1 > $start[0] Then ExitLoop 2 ;Exit the loop here instead.
    Next
WEnd
$Array2[0] = Int($1/(UBound($Array2) - 1))
_ArrayDisplay($Array2, "Unique")

I also added an _ArrayUnique() to my version to get rid of duplicates in the string:

Edit: After adding _ArrayUnique I made my version into a function so I could easily test for speed. Turns out it's fairly fast considering the use of arrays. The original with _ArrayUnique is in the spoiler.

#include <array.au3>
Local $aReturn = _RandomAssign("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,z,z,z,Z",5,",")
_ArrayDisplay($aReturn)

;  #FUNCTION#  ====================================================================================================================
; Name...........: _RandomAssign
; Description ...: Distributes a string of characters randomly over an array of specified size. (as evenly as possible)
; Syntax.........: _RandomAssign($sValues ,$iGroups [,$sDelim = Default])
; Parameters ....: $sValues     - A delimited string of characters to distribute
;               $iGroups        - The number of elements to distribute the characters over
;                   $sDelim     - [optional] The delimiter used in the string. (single  character only atm) (Default is Opt("GUIDataSeparatorChar"), which is  "|" unless changed")
; Return values .: Success - And array of $iGroups elements, with the characters randomly distributed over it.
;               Failure - 0, sets @error:
;               |1 - Invalid value for $iGroups
;               |2 - Delimiter is not found in string.
; Author ........: Tvern
;   ===============================================================================================================================

Func _RandomAssign($sValues,$iGroups, $sDelim = Default)
    If $iGroups < 1 Then Return SetError(1,0,0)
    $sDelim = String($sDelim)
    Switch $sDelim
        Case "Default", "-1", ""
            $sDelim = Opt("GUIDataSeparatorChar")
    EndSwitch
    Local $aSource = StringSplit($sValues,$sDelim)
    If @error Then Return SetError(2,0,0)
    Local $rRow, $Temp
    Local $aDest[$iGroups]
    $aSource = _ArrayUnique($aSource,1,1,1)
    For $iRow = 1 To $aSource[0]
        $rRow = Random(1, $aSource[0], 1)
        $Temp = $aSource[$iRow]
        $aSource[$iRow] = $aSource[$rRow]
        $aSource[$rRow] = $Temp
    Next
    While 1
        For $i = 0 To $iGroups -1
            $aDest[$i] &= $aSource[$aSource[0]]
            If $aSource[0] = 1 Then ExitLoop 2
            If $aSource[0] > $iGroups Then $aDest[$i] &= $sDelim
            $aSource[0] -= 1
        Next
    WEnd
    For $iRow = 0 To $iGroups-1
        $rRow = Random(0, $iGroups-1, 1)
        $Temp = $aDest[$iRow]
        $aDest[$iRow] = $aDest[$rRow]
        $aDest[$rRow] = $Temp
    Next
    Return $aDest
EndFunc

#include <array.au3>
Global $iDestCount = 5 ; the amount of elements you want to distribute the letters over.
Global $aSource = StringSplit("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,z,z,z,Z",",") ; the array of letters (source)
Global $aDest[$iDestCount] ;the destination.

$aSource = _ArrayUnique($aSource,1,1,1);No Duplicates (Set it to case sensitive atm)
_ArrayRandom($aSource,1) ;This way all letters will be used exactly once.

While 1
    For $i = 0 To $iDestCount -1
        $aDest[$i] &= $aSource[$aSource[0]]
        If $aSource[0] = 1 Then ExitLoop 2 ;exit when all letters are distributed
        If $aSource[0] > $iDestCount Then $aDest[$i] &= "," ;add a delimiter if another letter is expected.
        $aSource[0] -= 1
    Next
WEnd

_ArrayDisplay($aDest,"Distributed letters over " & $iDestCount & " elements")


;  #FUNCTION#  ====================================================================================================================
; Name...........: _ArrayRandom
; Description ...: Randomize the row order of (part of) a 1D or 2D array.
; Syntax.........: _ArrayRandom(ByRef $avArray, $iStart = 0, $iEnd = 0)
; Parameters ....: $avArray     - Array to randomize
;               $iStart     - [optional] Index of array to start at
;               $iEnd       - [optional] Index of array to stop at
; Return values .: Success - 1
;               Failure - 0, sets @error:
;               |1 - $avArray is not an array
;               |2 - $iStart is greater than $iEnd
; Author ........: Tom Vernooij
; Modified.......:
; Remarks .......: Based on Yashied's method
; Related .......:
; Link ..........:
; Example .......: No
;   ===============================================================================================================================
Func _ArrayRandom(ByRef $avArray, $iStart=0, $iEnd=0)
    If Not IsArray($avArray) Then Return SetError(1,0,0)

    Local $iRow, $iCol, $rRow, $Temp, $numCols = UBound($avArray,2), $Ubound = UBound($avArray) -1

    ; Bounds checking
    If $iEnd < 1 Or $iEnd > $UBound Then $iEnd = $UBound
    If $iStart < 0 Then $iStart = 0
    If $iStart > $iEnd Then Return SetError(2, 0, 0)

    ;   for 2 dimentional arrays:
    If $numCols Then
        For $iRow = $iStart To $iEnd ;for each row...
            $rRow = Random($iStart, $iEnd, 1) ;...select a random row
            For $iCol = 0 To $numCols -1    ;swich the values for each cell in the rows
                $Temp = $avArray[$iRow][$iCol]
                $avArray[$iRow][$iCol] = $avArray[$rRow][$iCol]
                $avArray[$rRow][$iCol] = $Temp
            Next
        Next

    ;   for 1 dimentional arrays:
    Else
        For $iRow = $iStart To $iEnd ;for each cell...
            $rRow = Random($iStart, $iEnd, 1) ;...select a random cell
            $Temp = $avArray[$iRow] ;switch the values in the cells
            $avArray[$iRow] = $avArray[$rRow]
            $avArray[$rRow] = $Temp
        Next
    EndIf
    Return 1
EndFunc

Edited by Tvern
Link to comment
Share on other sites

Here is a fix for JoHanatCent's script: (problem was in the last While)

I also added an _ArrayUnique() to my version to get rid of duplicates in the string:

Edit: After adding _ArrayUnique I made my version into a function so I could easily test for speed. Turns out it's fairly fast considering the use of arrays. The original with _ArrayUnique is in the spoiler.

Thank you Tvern.

SBTW ... I like your solution(s) too.

" "

Edited by JoHanatCent
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...