## Recommended Posts

I am working on a complex sorting script in my lab and I've been having some trouble trying to figure out how to tackle the program with AutoIt. I basically have a long list of possible combinations (576 elements) that I need to split into 6 smaller lists (96 elements). Each element consists of a short array of 6 different letters. The first half of the array (list element) consists of 3 letters made up of any combination of 4 letters (A,B,C, or D) but none of the letters may repeat in that instance. The second half of the array also consists of 3 letters made up of any combination of 4 other letters (E,F,G, or H) with no repeating letters for that element . Here are some possible examples:

ABCEFG

DBCEFG

If my math is correct, that should make 576 possible combinations assuming order matters (4 letters x 3 letters x 2 letters in the first half multiplied by 4 letters x 3 letters x 2 letters in the second half). The sort function will start out with a long list of 576 of these unique elements which is will try to split up into 6 smaller lists consisting of 96 elements. Here's the complex sort part. The smaller lists need to be counterbalanced so that there are an equal number of A's, B's, C's, D's, E's, F's, G's, and H's in them. I already know every possible combination and have written all 576 of them out in Excel, I just need to find a way to have a fancy sort script split it up so everything is counterbalanced. I have already written it out by hand using 3 possible letters rather than 4 for 4 spots (a 4 character array for each element) rather than 6 so I know its doable. Any help would be greatly appreciated!

Edited by Kapz

Easy:

Do

PuzzledLook()

Until \$forever

##### Share on other sites

Its a nice challenge and thought i had some logic for it but didn;t work as yet .... Live for the present,
Dream of the future,
Learn from the past. ##### Share on other sites

Okay I think you are using the term "array" too loosely.

Each element consists of a short array of 6 different letters.

I'm assuming you mean "string" and not an actual array???

The first half of the array (list element) consists of 3 letters made up of any combination of 4 letters (A,B,C, or D) but none of the letters may repeat in that instance. The second half of the array also consists of 3 letters made up of any combination of 4 other letters (E,F,G, or H) with no repeating letters for that element .

Again when you say "first half of the array" are you meaning first half of the string?

##### Share on other sites

This script generated the combinations that is talked about.

They need to be split into 6 stacks of 96 record in which each letter appear 72 timers ... ```FileDelete("test.txt")
; each char (8) needs to be in each file(6) 72 times
Dim \$Counters
Dim \$A1 = ["A", "B", "C", "D"]
Dim \$A2 = ["E", "F", "G", "H"]
\$count = 0
For \$x1 = 0 To 3
For \$x2 = 0 To 3
For \$x3 = 0 To 3
For \$y1 = 0 To 3
For \$y2 = 0 To 3
For \$y3 = 0 To 3
; Ensure different characters
If \$x1 = \$x2 Or \$x1 = \$x3 Or \$x2 = \$x3 Then ContinueLoop
If \$y1 = \$y2 Or \$y1 = \$y3 Or \$y2 = \$y3 Then ContinueLoop
; Check the counters to ensure that each char is only 72 times in each file
FileWriteLine("test.txt", \$A1[\$x1] & \$A1[\$x2] & \$A1[\$x3] & \$A2[\$y1] & \$A2[\$y2] & \$A2[\$y3])
Next
Next
Next
Next
Next
Next```
Edited by Jos

Live for the present,
Dream of the future,
Learn from the past. ##### Share on other sites

Wow.

... (eyes begin to refocus) OK, I dig the concept of this one. I've got a few process flow thoughts running in my head now on how to pull it off, I'll post whatever snippets I come up with.

Edit: lol, nm - apparently in the time it took me to read the description, Jos tore right through the issue (and much simpler, cleaner code than I would have had).

Edited by Monamo

- MoChr(77)& Chr(97)& Chr(100)& Chr(101)& Chr(32)& Chr(121)& Chr(97)& Chr(32)& Chr(108)& Chr(111)& Chr(111)& Chr(107)-------I've told you 100,000 times not to exaggerate!-------Don't make me hit you with my cigarette hand...-------My scripts:Random Episode Selector, Keyboard MouseMover, CopyPath v2.1, SmartRename for XP,Window Tracer[sup]New![/sup]

##### Share on other sites

I was on the right track too until Jos posted so I will try to work with his version. There are question marks floating over my head.

##### Share on other sites

Do I get a prize?

EDIT: All fixed now

```#include <array.au3>

Dim \$masterArray

\$size = 96

Dim \$subArray1[\$size]
Dim \$subArray2[\$size]
Dim \$subArray3[\$size]
Dim \$subArray4[\$size]
Dim \$subArray5[\$size]
Dim \$subArray6[\$size]

; each char (8) needs to be in each file(6) 72 times
Dim \$A1 = ["A", "B", "C", "D"]
Dim \$A2 = ["E", "F", "G", "H"]
\$count = 0
For \$x1 = 0 To 3
For \$x2 = 0 To 3
For \$x3 = 0 To 3
For \$y1 = 0 To 3
For \$y2 = 0 To 3
For \$y3 = 0 To 3
; Ensure different characters
If \$x1 = \$x2 Or \$x1 = \$x3 Or \$x2 = \$x3 Then ContinueLoop
If \$y1 = \$y2 Or \$y1 = \$y3 Or \$y2 = \$y3 Then ContinueLoop

; Check the counters to ensure that each char is only 72 times in each file
\$masterArray[\$count] = \$A1[\$x1] & \$A1[\$x2] & \$A1[\$x3] & \$A2[\$y1] & \$A2[\$y2] & \$A2[\$y3]
;\$masterArray[\$count] = Asc(\$A1[\$x1]) + Asc(\$A1[\$x2]) + Asc(\$A1[\$x3]) + Asc(\$A2[\$y1]) + Asc(\$A2[\$y2]) + Asc(\$A2[\$y3])
\$masterArray[\$count] = GenerateChecksum(\$masterArray[\$count])
\$count += 1
Next
Next
Next
Next
Next
Next

Redim \$masterArray[\$count]

_ArraySort (\$masterArray, 0,0,0,2,1)

;_Arraydisplay(\$masterArray)

\$X = 0
For \$multiplier = 0 to 15
For \$Y = 1 to 6
ConsoleWrite("::::::::::::::::::::::::::::::::::::::::::::::ARRAY " & \$Y & @CRLF & @CRLF)
For \$Z = 1 to 6
\$element = \$Z + (\$multiplier * 6) -1

Switch \$Y
Case 1
\$subArray1[\$element] = \$masterArray[\$X]
Case 2
\$subArray2[\$element] = \$masterArray[\$X]
Case 3
\$subArray3[\$element] = \$masterArray[\$X]
Case 4
\$subArray4[\$element] = \$masterArray[\$X]
Case 5
\$subArray5[\$element] = \$masterArray[\$X]
Case 6
\$subArray6[\$element] = \$masterArray[\$X]
EndSwitch
ConsoleWrite("Y: " & \$Y & " Z: " & \$Z & " X: " & \$X & @CRLF)
ConsoleWrite("Element: " & \$element & @CRLF)
\$X += 1
Next
Next
Next

VerifyCounts(\$subArray1)

;_Arraydisplay(\$subArray1)
;_Arraydisplay(\$subArray2)
;exit
;_Arraydisplay(\$subArray3)
;_Arraydisplay(\$subArray4)
;_Arraydisplay(\$subArray5)
;_Arraydisplay(\$subArray6)

Func VerifyCounts(\$theArray)

\$dictionaryObj = ObjCreate("Scripting.Dictionary")
For \$X = 0 to Ubound(\$theArray) - 1
\$tempArray = StringSplit(\$theArray[\$X], "")
For \$Y = 1 to \$tempArray
\$dictionaryObj.Item(\$tempArray[\$Y]) = \$dictionaryObj.Item(\$tempArray[\$Y]) + 1
Next
Next

#include <GUIConstants.au3>

GUICreate("Character Occurrences", 200)  ; will create a dialog box that when displayed is centered
GUISetState (@SW_SHOW)       ; will display an empty dialog box

\$listview = GUICtrlCreateListView ("Character | Occurrences",10,10,180,380,\$LVS_SORTASCENDING)
For \$key In \$dictionaryObj.Keys()
GUICtrlCreateListViewItem(\$key & "|" & \$dictionaryObj.Item(\$key),\$listview)
Next

; Run the GUI until the dialog is closed
While 1
\$msg = GUIGetMsg()
If \$msg = \$GUI_EVENT_CLOSE Then ExitLoop
Wend
EndFunc

Func GenerateChecksum(\$theString)
\$checksum = 0
\$tempArray = StringSplit(\$theString, "")
For \$X = 1 to \$tempArray
Switch \$tempArray[\$X]
Case "A"
\$checksum += 2
Case "B"
\$checksum += 4
Case "C"
\$checksum += 8
Case "D"
\$checksum += 16
Case "E"
\$checksum += 32
Case "F"
\$checksum += 64
Case "G"
\$checksum += 128
EndSwitch
Next

Return \$checksum
EndFunc```

Explanation:

1. All possible strings are placed into a 2 dimensional array. Dimension 1 is the string itself and dimension 2 is a "checksum" of the string which should always be the same if you were to shuffle the string.

2. The array is sorted by the checksum, which effectively gives you 16 different checksums times 36 elements. To distribute an equal amount of elements from each checksum we will form the 6 arrays by taking 6 elements from each checksum "group".

3. A loop is run through the master array in 16 sections, each section being a unique checksum. Each section will be read in sub-sections of 36 elements and said elements are copied into their respective array.

Edited by weaponx

##### Share on other sites

Did you check the count in each Array for A,B,C,D,E and F ? Don't think they are 72 in each array . Live for the present,
Dream of the future,
Learn from the past. ##### Share on other sites

Think this one is what is wanted..... was a nice brain buster ```FileDelete("Segment0.txt")
FileDelete("Segment1.txt")
FileDelete("Segment2.txt")
FileDelete("Segment3.txt")
FileDelete("Segment4.txt")
FileDelete("Segment5.txt")
; each char (8) needs to be in each file(6) 72 time
Dim \$Counters
Dim \$A1 = ["A", "B", "C", "D"]
Dim \$A2 = ["E", "F", "G", "H"]
\$count = 0
For \$x1 = 0 To 3
For \$x2 = 0 To 3
For \$x3 = 0 To 3
For \$y1 = 0 To 3
For \$y2 = 0 To 3
For \$y3 = 0 To 3
; Ensure different characters
If \$x1 = \$x2 Or \$x1 = \$x3 Or \$x2 = \$x3 Then ContinueLoop
If \$y1 = \$y2 Or \$y1 = \$y3 Or \$y2 = \$y3 Then ContinueLoop
; Check the counters to ensure that each char is only 72 times in each file
\$LowestNr = 9999
\$LowestFl = 6
\$sf = 0
Dim \$Full =[0,0,0,0,0,0]     ; keep track of full tables
Dim \$Lowest =[99,99,99,99,99,99]; Find lowest count in tables
Dim \$Total =[0,0,0,0,0,0]       ; Find total counts of the whole table
For \$f = 0 To 5
For \$c = 0 To 7
If \$c < 4 Then \$tc = \$A1[\$c]
If \$c > 3 Then \$tc = \$A2[\$c - 4]
If StringInStr(\$A1[\$x1] & \$A1[\$x2] & \$A1[\$x3] & \$A2[\$y1] & \$A2[\$y2] & \$A2[\$y3], \$tc) Then
\$Total[\$f] += \$Counters[\$c][\$f]
; Found full table ?
If \$Counters[\$c][\$f] > 71 Then
\$full[\$f] = 1
ContinueLoop 2
EndIf
; tack lowest count
If \$Counters[\$c][\$f] < \$Lowest[\$f] Then \$Lowest[\$f] = number(\$Counters[\$c][\$f])
EndIf
Next
Next
; store result in table with lowest count and lowest total count
\$lows = 99
\$LowestFl = 6
\$Totals = 999
For \$x = 0 to 5
If \$full[\$x] <> 1 and \$Lowest[\$x] <= \$lows and \$Totals > \$Total[\$x] then
\$lows = \$Lowest[\$x]
\$Totals = \$Total[\$x]
\$LowestFl = \$x
EndIf
Next
If \$LowestFl < 6 Then
; Update the counters of the found table
For \$c = 0 To 7
If \$c < 4 Then \$tc = \$A1[\$c]
If \$c > 3 Then \$tc = \$A2[\$c - 4]
If StringInStr(\$A1[\$x1] & \$A1[\$x2] & \$A1[\$x3] & \$A2[\$y1] & \$A2[\$y2] & \$A2[\$y3], \$tc) Then
\$Counters[\$c][\$LowestFl] += 1
EndIf
Next
FileWriteLine("Segment" & \$LowestFl & ".txt", \$A1[\$x1] & \$A1[\$x2] & \$A1[\$x3] & \$A2[\$y1] & \$A2[\$y2] & \$A2[\$y3])
Else
ConsoleWrite("Error not able to assign this combo:" & \$A1[\$x1] & \$A1[\$x2] & \$A1[\$x3] & \$A2[\$y1] & \$A2[\$y2] & \$A2[\$y3])
EndIf
Next
Next
Next
Next
Next
Next
Consolewrite("###################################" & @CRLF)
Consolewrite("### Checkking the counts table ####" & @CRLF)
Consolewrite("###################################" & @CRLF)
For \$f = 0 To 5
For \$c = 0 To 7
ConsoleWrite(\$Counters[\$c][\$f] & " ")
Next
ConsoleWrite(@CRLF)
Next```

Live for the present,
Dream of the future,
Learn from the past. ##### Share on other sites

Did you check the count in each Array for A,B,C,D,E and F ? Don't think they are 72 in each array . I see what you mean. I guess I assumed there was a balanced number of each checksum after the sort (96 each times 6). I will try to fix it.

##### Share on other sites

Jos... weaponx...

That code looks like fine art. Sorry... couldn't help myself.

##### Share on other sites

The script I posted is all good now. 72 instances of each character in each array.

##### Share on other sites

Wow, that is amazing! I thought about different ways to approach the problem and I even wrote it out by hand to make sure it was doable using 3 letters for both halves (A,B,C and E,F,G) instead of 4 letters with only 4 possible spots instead of 6 in the string....and that worked. When I tried to use a 6 letter string with 4 possible characters for each half, it became much mroe complicated. I will test the code today, but thank you so very much in advance, you guys are freaken awesome!

##### Share on other sites

Thank you so very much for your help Jos and everyone else, the script worked perfectly! Now, on to fun experiments in the lab!

##### Share on other sites

This may seem very simple but I was wondering if the script could be modified to randomize what each of the 6 groups consists of? For example, the first group may have something like ABCEFG but that will never exist in the second group unless the program can be randomized to move things around into different groups. I know this is possible, I'm just not sure of an easy way to accomplish it with the script that Jos came up with? Maybe if the original list that is created is randomised first and then sorted into 6 groups? Thanks again for all of yalls help!

##### Share on other sites

I'm not really sure about what you are wanting. We have 2 pools of characters from which strings are formed, ABCD and EFGH. Are you saying you want to scramble those so it can be like DEAH BGCF???

##### Share on other sites

I'm not really sure about what you are wanting. We have 2 pools of characters from which strings are formed, ABCD and EFGH. Are you saying you want to scramble those so it can be like DEAH BGCF???

Let me provide a brief example of what I'm referring to. So below are two of the 6 groups with only a few items instead of 96:

ABCEFG

BDAEFG

BCAHGE

ABCFEG

CDBHEF

So any one of the three combinations in the first group will never exist in the second group (ex: ABCEFG) since everything has to be counter-balanced within that group (same number of A's, same number of G's ,etc). However, you could switch up the groups by swapping the first element (ABCEFG) in group one with the first element in group 2 (ABCFEG) since they have the exact same element, just a different order. This will allow for the 6 groups to exist with everything counterbalanced within the groups. I'm just not sure how to accomplish this with the script. Does it make more sense to do this as it creates the list or would it be better to create another script that can go through and swap items out, further randomizing the lists within each of the 6 groups (of 96 elements)?

Thanks!

##### Share on other sites

Here is the script that I came up with to accomplish what I was looking for, maybe the code can explain it better than I can with words. Sorry if my code is a bit rusty, I'm sure there is a prettier and more efficient way to accomplish this. Thanks!

```#include <File.au3>
FileOpen("Segment0.txt", 1)
FileOpen("Segment1.txt", 1)
FileOpen("Segment2.txt", 1)
FileOpen("Segment3.txt", 1)
FileOpen("Segment4.txt", 1)
FileOpen("Segment5.txt", 1)

;randomization loop max
\$max = 1000

;counter of voided loops (\$max - \$s1 = true number of loops)
\$s1 = 0

;Loop to call swap function with random list picking
For \$count = 1 to \$max
\$t1 = int(random(0,5))
\$t2 = int(random(0,5))
If \$t1 = \$t2 Then
\$s1 = \$s1 + 1
Else
Swap("Segment" & \$t1 & ".txt","Segment" & \$t2 & ".txt")
EndIf
Next

;Close all files when done
FileClose("Segment0.txt")
FileClose("Segment1.txt")
FileClose("Segment2.txt")
FileClose("Segment3.txt")
FileClose("Segment4.txt")
FileClose("Segment5.txt")

;Check to make sure that there are 72 occurences of each unique letter within each txt file
check("Segment0.txt")
check("Segment1.txt")
check("Segment2.txt")
check("Segment3.txt")
check("Segment4.txt")
check("Segment5.txt")

;Write out the number of voided loops
ConsoleWrite(\$s1)

;Swap function to swap out one element in a txt file with a similiar element in another txt file
Func Swap(\$list1, \$list2)
\$stop = 0

For \$d = 1 to 96
\$rand2 = int(Random(1,96))

For \$c = 1 to 96
\$rand = int(Random(1,96))
\$num = StringRegExp(\$x1, StringLeft(\$y1,1))
\$num = \$num + StringRegExp(\$x1, StringRight(StringLeft(\$y1,2),1))
\$num = \$num + StringRegExp(\$x1, StringRight(StringLeft(\$y1,3),1))
\$num = \$num + StringRegExp(\$x1, StringRight(StringLeft(\$y1,4),1))
\$num = \$num + StringRegExp(\$x1, StringRight(StringLeft(\$y1,5),1))
\$num = \$num + StringRegExp(\$x1, StringRight(StringLeft(\$y1,6),1))

;If match has identical letters but not necessarily in the same order then replace and exit loop
If \$num = 6 Then
_FileWriteToLine (\$list1, \$rand, \$y1 ,1)
_FileWriteToLine (\$list2, \$rand2, \$x1 ,1)
\$stop = \$stop + 1
ExitLoop
EndIF

\$num = 0
Next

If \$stop = 1 Then
ExitLoop
EndIf

Next

EndFunc

Func Check(\$checklist)
\$A = 0
\$B = 0
\$C = 0
\$D = 0
\$E = 0
\$F = 0
\$G = 0
\$H = 0
For \$t = 1 to 96
If StringRegExp(FileReadLine(\$checklist,\$t), "A") = 1 Then
\$A = \$A + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "B") = 1 Then
\$B = \$B + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "C") = 1 Then
\$C = \$C + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "D") = 1 Then
\$D = \$D + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "E") = 1 Then
\$E = \$E + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "F") = 1 Then
\$F = \$F + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "G") = 1 Then
\$G = \$G + 1
EndIf
If StringRegExp(FileReadLine(\$checklist,\$t), "H") = 1 Then
\$H = \$H + 1
EndIf
Next
ConsoleWrite("A=" & \$A & " | B=" & \$B & " | C=" & \$C & " | D=" & \$D & " | E=" & \$E & " | F=" & \$F & " | G=" & \$G & " | H=" & \$H & @CRLF)
EndFunc```

## Create an account

Register a new account

×

• Wiki

• Back

• #### Beta

• Git
• FAQ
• Our Picks
×
• Create New...