Sign in to follow this  
Followers 0
michaelslamet

[SOLVED] Random Assignment Question

12 posts in this topic

#1 ·  Posted (edited)

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

Share this post


Link to post
Share on other sites



With Random you'll get duplicates from array1.

Is that what you want or should duplicates be removed?


Share this post


Link to post
Share on other sites

Hi JoHanatCent,

The duplicate should removed.

Thanks for reply and help :)

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

I tested it just now, and wow it works perfectly :)

I'm going to use this part of code/logic in my app.

Thanks so much, Tvern! :)

Share this post


Link to post
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")

Share this post


Link to post
Share on other sites

Thanks JoHanatCent :)

will try it.

Many thanks to both of you!

Share this post


Link to post
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 :)

Share this post


Link to post
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?


Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

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

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

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

Share this post


Link to post
Share on other sites

Thanks a lot for both of you, John and Tvern.

I'm able to finish my small app with your help :)

Share this post


Link to post
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
Sign in to follow this  
Followers 0