|
Post by B+ on Apr 18, 2021 0:34:40 GMT
Every time code discovers duplicate in a list it correctly gets a new string to test BUT right after that it exits main For loop before finishing the loop???
I tested this code in another Basic and it works fine.
' Ladder No Duplicates 'B+ 2021-04-17 build 2 Lists without duplicates nItems = 10 'per list
[restart] dim list1$(nItems), list2$(nItems) i1 = 1 : i2 = 1 : ia = 1 ' modify to base 1 arrays indexes to each list and all$ = where index
'create lists use same list for testing this is same for both methods for i = 1 to nItems ' NO Duplicates in list k = i [doagain] test$ = RndStr$() print "test$ = ";test$ if i > 1 then for j = 1 to k - 1 if test$ = list1$(j) then goto [doagain] next j end if list1$(i) = test$
[testAgain2] test2$ = RndStr$() print "test2$ = ";test2$ if i > 1 then for j = 1 to k - 1 if test2$ = list2$(j) then goto [testAgain2] next j end if list2$(i) = test2$ print i, list1$(i), list2$(i) 'check raw OK
next i input "This should have printed 10 items. Quit? enter y "; quit$ if quit$ = "y" then end else goto [restart] end
Function RndStr$() 'limit possibilities to increase duplicate rl = Int(Rnd(0) * 3) + 1 b$ = "" For k = 1 To rl b$ = b$ + Mid$("ABCDEFEFGHIJKLM", Int(Rnd(0) * 15) + 1, 1) Next RndStr$ = b$ End Function
|
|
|
Post by tsh73 on Apr 18, 2021 5:42:42 GMT
Well I see you leave FOR with goto, it is known that JB/LB doesn't like it (probably stack corruption)
Rewrote with EXIT FOR, works for me
' Ladder No Duplicates 'B+ 2021-04-17 build 2 Lists without duplicates nItems = 10 'per list
[restart] dim list1$(nItems), list2$(nItems) i1 = 1 : i2 = 1 : ia = 1 ' modify to base 1 arrays indexes to each list and all$ = where index
'create lists use same list for testing this is same for both methods for i = 1 to nItems ' NO Duplicates in list k = i [doagain] test$ = RndStr$() print "test$ = ";test$ if i > 1 then doAgain=0 for j = 1 to k - 1 if test$ = list1$(j) then doAgain =1:exit for next j if doAgain goto [doagain] end if list1$(i) = test$
[testAgain2] test2$ = RndStr$() print "test2$ = ";test2$ if i > 1 then testAgain2=0 for j = 1 to k - 1 if test2$ = list2$(j) then testAgain2=1: exit for next j if testAgain2 then [testAgain2] end if list2$(i) = test2$ print i, list1$(i), list2$(i) 'check raw OK
next i input "This should have printed 10 items. Quit? enter y "; quit$ if quit$ = "y" then end else goto [restart] end
Function RndStr$() 'limit possibilities to increase duplicate rl = Int(Rnd(0) * 3) + 1 b$ = "" For k = 1 To rl b$ = b$ + Mid$("ABCDEFEFGHIJKLM", Int(Rnd(0) * 15) + 1, 1) Next RndStr$ = b$
End Function
|
|
|
Post by B+ on Apr 18, 2021 15:41:18 GMT
Aha! OK thankyou! Now I vaguely recall something like this maybe, I guess I never paid attention because I try never to use GOTO.
Now I wonder, is it just in FOR loop, how about WHILE or DO? Let the experiments begin... ;-))
I will suppose a GOSUB would be fine because that returns you right back to loop you are in. But that would not work here you'd have to cycle through loop again with new test string.
|
|
|
Post by B+ on Apr 18, 2021 16:46:37 GMT
Yeah WHILE instead of FOR loops seem safe to exit with GOTO and restart WHILE again over and over without reaching WEND.
Here I just substituted in WHILE loops for the inner FOR loops:
' Freaky For Fix with WHILE test.txt 'B+ 2021-04-18 build 2 Lists without duplicates nItems = 10 'per list
[restart] dim list1$(nItems), list2$(nItems) i1 = 1 : i2 = 1 : ia = 1 ' modify to base 1 arrays indexes to each list and all$ = where index
'create lists use same list for testing this is same for both methods for i = 1 to nItems ' NO Duplicates in list [doagain] test$ = RndStr$() print "test$ = ";test$ if i > 1 then j = 1 while j < i if test$ = list1$(j) then goto [doagain] j = j + 1 wend end if list1$(i) = test$
[testAgain2] test2$ = RndStr$() print "test2$ = ";test2$ if i > 1 then j = 1 while j < i if test2$ = list2$(j) then goto [testAgain2] j = j + 1 wend end if list2$(i) = test2$ print i, list1$(i), list2$(i) 'check raw OK
next i input "This should have printed 10 itmes. Quit? enter y "; quit$ if quit$ = "y" then end else goto [restart] end
Function RndStr$() 'limit possibilities to increase duplicate rl = Int(Rnd(0) * 3) + 1 b$ = "" For k = 1 To rl b$ = b$ + Mid$("ABCDEFEFGHIJKLM", Int(Rnd(0) * 15) + 1, 1) Next RndStr$ = b$ End Function
I never suspected FOR loops using a stack. When I built my interpreter, I used the end of loop marker as like a line that said GOTO (working upwards) the start of loop at the same level depth as this marker.
|
|
|
Post by tsh73 on Apr 18, 2021 18:04:21 GMT
Then I was experimenting around this (long time ago) I remember WHILE had some problems as well. It might be fixed since then. Or my case was differed from yours. I cannot probably find it (it was really long time ago).
I think it goes on creator's whim. It could be used, probably it would give some benefits for nested loops.
|
|
|
Post by B+ on Apr 18, 2021 18:27:43 GMT
Well if WHILE didn't work my next resource would be to use line [Labels] and GOTO to make a handmade loop.
FOR loop is harder to code because of the index variable that has to be tracked but a WHILE shouldn't need to track anything, under-the-hood I mean like with a stack, the exit condition and "index" variable(s) are coded in the program.
|
|
|
Post by tsh73 on Apr 18, 2021 20:30:09 GMT
*in this very BASIC - other languages/implementations may differ* Both FOR and WHILE do work. They just happen not to support breaking from loop with GOTO. There is EXIT FOR, EXIT WHILE, EXIT DO operators to cleanly get out of loop. Use them and will not have a problem (or it was the idea, anyway)
|
|
|
Post by B+ on Apr 18, 2021 22:04:04 GMT
But WHILE is working with a GOTO from inside it to code line above it without EXIT WHILE.
I posted code 3 (or 4) replies up and am using it without incident in my "ladder" code tests.
Turns out I am going to need a faster way to come up with lists of 10,000 or more items probably 250,000 or more. As more items are needed this method bogs down almost to a stop looking for duplicates.
Time for a shuffle and draw from a deck of strings. I am setting up to use a list of permutations already created in a file: 362,880 perms of 9 digits, then I can make lists of 250,000 each that is sure to be non duplicate within list but lot's of duplication between lists.
|
|
|
Post by tsh73 on Apr 20, 2021 9:23:47 GMT
Sorry it proves just one thing: you are lucky. I pretty sure While has some problems with GOTO out of loop Here's sample
i=0 while i <3 print i i=i+1 j=0 while j<4 print , j j=j+1 '1) exit while, no problems 'if j=2 then print "*":exit while '2) goto [out1], weirdiness ahoy 'if j=2 then print "*":goto [out1] wend goto [skip] [out1] print "just got out" [skip] wend print "over"
Without any jump out of loop
0 0 1 2 3 1 0 1 2 3 2 0 1 2 3 over
With EXIT WHILE
0 0 1 * 1 0 1 * 2 0 1 * over
with GOTO out of loop
0 0 1 * just got out 2 3 1 0 1 * just got out 2 3 2 0 1 * just got out 2 3 over
If I step it with DEBUG, I see it do jump (it prints "just got out"), but after OUTER wend it goes to INNER while. So I'd rather not risk using GOTO to jump out of WHILE on this BASIC.
|
|
|
Post by B+ on Apr 20, 2021 18:09:21 GMT
Aha! You're right and here is the clue as to how I got lucky:
i=0 for i = 0 to 2 print i
j=0 while j<4 print , j j=j+1 '1) exit while, no problems 'if j=2 then print "*":exit while '2) goto [out1], weirdiness ahoy 'if j=2 then print "*":goto [out1] wend goto [skip] [out1] print "just got out" [skip] next print "over"
How to get lucky: go back to before While you jumped out of, tell it j is done to get same output as with exit while:
i=0 for i = 0 to 2 print i
j=0 goto [skip] [out1] j = 4 [skip] while j<4 print , j j=j+1 '1) exit while, no problems 'if j=2 then print "*":exit while '2) goto [out1], weirdiness ahoy if j=2 then print "*":goto [out1] wend next print "over"
|
|
|
Post by B+ on Apr 20, 2021 18:34:31 GMT
But that's silly because workaround is more work not to mention playing with fire, just do this:
i=0 while i <3 print i i=i+1 j=0 [whilejIslessThan4] print , j j=j+1 '2) goto [out1], weirdiness ahoy if j=2 then print "*":goto [out1] if j < 4 then goto [whilejIslessThan4] goto [skip] [out1] print "just got out" [skip] wend print "over"
|
|