michaelslamet Posted March 16, 2011 Posted March 16, 2011 (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 March 19, 2011 by michaelslamet
JoHanatCent Posted March 16, 2011 Posted March 16, 2011 With Random you'll get duplicates from array1. Is that what you want or should duplicates be removed?
michaelslamet Posted March 16, 2011 Author Posted March 16, 2011 Hi JoHanatCent, The duplicate should removed. Thanks for reply and help
Tvern Posted March 16, 2011 Posted March 16, 2011 I was thinking something like this: expandcollapse popup#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.
michaelslamet Posted March 16, 2011 Author Posted March 16, 2011 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!
JoHanatCent Posted March 16, 2011 Posted March 16, 2011 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")
michaelslamet Posted March 16, 2011 Author Posted March 16, 2011 Thanks JoHanatCent will try it. Many thanks to both of you!
michaelslamet Posted March 17, 2011 Author Posted March 17, 2011 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
JoHanatCent Posted March 17, 2011 Posted March 17, 2011 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?
Tvern Posted March 17, 2011 Posted March 17, 2011 (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. expandcollapse popup#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 expandcollapse popup#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 March 17, 2011 by Tvern
JoHanatCent Posted March 17, 2011 Posted March 17, 2011 (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 March 17, 2011 by JoHanatCent
michaelslamet Posted March 19, 2011 Author Posted March 19, 2011 Thanks a lot for both of you, John and Tvern. I'm able to finish my small app with your help
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now