Ive been trying to write Access VBA code to automate the addition of replicates for germination tests.
Basically I have a form where I enter the total number of Reps (NoofReps) and the number of seeds per rep (RepSize) (e.g. 50 seeds). For each record added I want it to automatically add a record for each rep and automatically calc the Rep Number (i.e if i have 4 reps then it should add 4 records, numbered 1-4 reps) as well as the RepSize (e.g 50).
I have been trying out various loops based on information from this forum and other but am still getting errors with the number of records that it generates. I have tried both the "Do while" and "Do Until" but get the same result below either way.
Could someone please let me know where I am going wrong?...If i want 2 reps then it adds 2, If i want 3 then its 246, and if i want 4 it adds >30,000!!!
For the purposes of trying to fix the code I have started to type the number of reps manually into the code in the iNoofReps so that I know the error is in the code and not from the form.
Private Sub CmdAddReps3_Click()
Dim iRepNo As Integer ' stores the current value in the series
'Open the table
Set db = CurrentDb()
Set rstGReps = db.OpenRecordset("tblGReplicates")
' Initialise the variables
iRepNo = 1
iNoofReps = 3 'iNoofReps = Me.txtNoofReps
' Add the records using a loop
rstGReps.movefirst
Do 'Until rstGReps("RepNo") = (iNoofReps + 1) ' always want to include at least 1 repNo
rstGReps.AddNew
rstGReps("GTestID") = Me.GTestID
rstGReps("RepNo") = iRepNo
rstGReps("NoofSeed") = Me.txtNoOfSeeds
' Calculate the next RepNo value in the loop
iRepNo = iRepNo + 1
rstGReps.Update
rstGReps.moveNext
Loop Until rstGReps("RepNo") = (iNoofReps) + 1 ' so that the loop includes the final repNo.
MsgBox "Finished Looping"
rstGReps.Close
Set rstGReps = Nothing
Set db = Nothing
End Sub
Any help would be appreciated!!!
Well, you're moving next here: rstGReps.moveNext, and then you're comparing rstGReps("RepNo") = (iNoofReps) + 1 after moving next, thus being on an empty record, thus always equating to false.
Loop Until iRepNo = (iNoofReps) + 1 should fix it, then you're no longer referring to the recordset, which has already been set to the next record by the time you're referring to it.
You could also fix it by just eliminating this line:
rstGReps.moveNext
Since rstGReps.AddNew already moves the recordset to a new blank record, moving it forward after adding the record doesn't make much sense. If you remove it, you might want to remove the + 1 in Loop Until rstGReps("RepNo") = (iNoofReps) + 1
I have been working on this vb script for around an hour trying to get it to work there is many skype spammer scipts but i want to make one that includes a random number generator my script is this i call it at the moment "Skype_randizer_mk1"
If anyone would be able to take a look at it it would be greatly appreciated.
When i was posting this the website said i had to indent this so it may look a little strange
The Delay variable is the amount of time it will take to enter another number
I don't mind if this program makes only numerical values that is what i intend for it to do
set shell = createobject ("wscript.shell")
dim max
dim min
dim delay
max = 100
min = 1
delay = 0.00000001
for i = 1 to 5
randomize
intnumber = int((max - min + 1) * rnd + min )
wscript.echo intnumber
Next
for b=1 to delay
shell.sendkeys (intnumber)
wscript.sleep(delay)
if not isnumeric(delay) then
wscript.quit
end if
msgbox "You have 5 seconds to get to your inputbox."
wscript.sleep ( 5000 )
Next
You have lots of problems with your code:-
You should ALWAYS declare your variables using Dim: e.g. Dim shell
You are missing a Next for one of your For loops
Line 10 doesn't make much sense. It says: for b=1 to delay, but delay = 0.00000001, so your loop will never run. Also, why does this section even need to loop? I think you probably just want an If/Then/Else
Line 11 should probably say shell.SendKeys, not strshell.sendkeys as this is an uninitialised variable
Line 13 is checking for a numeric delay value. How will this ever be anything other than numeric when you are assigning a value of 0.00000001 on line 4 and it never changes. As a result, you will not exit the script until the for loop on line 5 has executed 5 times.
Here's part of my code.
<%
Dim lineData,fso,filea,fileb,filec
s=request.querystring("query")
set fso = Server.CreateObject("Scripting.FileSystemObject")
a(0,0)=0
a(1,0)=" - Entries in File A"
set filea = fso.OpenTextFile(Server.MapPath("FileA.txt"), 1, true)
do until lone.AtEndOfStream
lineData = lcase(filea.ReadLine())
if instr(lineData,s)>0 then
a(0,0)=a(0,0)+1
end if
Loop
a(0,1)=0
a(1,1)=" - Entries in File B"
set fileb = fso.OpenTextFile(Server.MapPath("FileB.txt"), 1, true)
do until mile.AtEndOfStream
lineData = lcase(fileb.ReadLine())
if instr(lineData,s)>0 then
a(0,1)=a(0,1)+1
end if
Loop
a(0,2)=0
a(1,2)=" - Entries in File C"
set filec = fso.OpenTextFile(Server.MapPath("FileC.txt"), 1, true)
do until payne.AtEndOfStream
lineData = lcase(filec.ReadLine())
if instr(lineData,s)>0 then
a(0,2)=a(0,2)+1
end if
Loop
%>
The code essentially looks for the number of entries in a text file. What I need is it to be sorted such that the file with the most number of entries comes first.
Suppose there are 10 entries in FileA, 12 in FileB and 7 in FileC. I'd like the output to be displayed like this:
12 - Entries in File B
10 - Entries in File A
7 - Entries in File C
I'm guessing it won't be too complicated since response.write(a(0,i)&a(1,i)) will work. I just need help with the loop or any sorting method if there is one.
Any help I can get in here will be much appreciated.
This will be a "neo-answer" that should help you get to where you want to go, both in the short- and long-term.
1) First, a suggestion for further reading to help you address this sort of problem in a more general way -- and to help you develop your "chops" as you go. You can Google the term "bubble sort" and get a whole host of interesting and mostly helpful input, but here's a link you probably will find most directly helpful, from a brief series of articles on sorting from the 4 Guys from Rolla site, which back in the day was THE place for quality writing on ASP:
https://web.archive.org/web/20211020153403/https://www.4guysfromrolla.com/webtech/011601-1.shtml
You will see that there is a link to an introductory article at the top of this one that covers one-dimensional array sorting, and I recommend it as well. For one, it introduces another sort method, QuickSort, and having multiple tools in your toolbox is almost never a bad idea. (As you will discover, bubble sorting is often the easiest to envision and implement, but because its performance is essentially linear based on the number of items being sorted, can become a performance problem on larger datasets.) Go ahead, check it out; I'll wait 'til you get back...
2) OK, to give you a more concrete approach to address your specific situation here, if the number of files you're reviewing isn't going to be too large, you can do a sort of "final pass" sort to present your results in the desired order.
First, you'll want to introduce a simple global counting variable up toward the top of your code:
dim intMaxEntries
intMaxEntries = 0
Then, at the end of each of your file-parsing runs, you'll want to check the number of entries against intMaxEntries and update intMaxEntries if the number of entries just read in is greater.
if a(0, 1) > intMaxEntries then
intMaxEntries = a(0, 1)
end if
You'll do right after each file reading loop, so the comparison in the above snippet would be done for a(0, 1), a(1, 1), and a(2, 1). More on that repetitive logic at the end.
After you've done all the file reads, intMaxEntries will have the maximum number of entries you've found in one of the files. Then, you can just step down from that value and print out entry counts in the correct order when they match your countdown:
dim i, j
for i = intMaxEntries to 0 step -1
for j = 0 to ubound(a) 'By default gives the upper bound of the 1st dimen.
if a(j, 1) = i then
Response.Write i & a(j, 2) & "<BR>"
end if
next j
next i
This is more than a bit of a hack, and I would encourage you to opt instead for doing a proper sort of your array so that you have something more generalizably useful, but it will work to get you where you want to go, especially if the number of files -- or the maximum number of entries -- isn't too large. You could also clean up my example by introducing the possibility of breaking out of the loops when all the files are accounted for, but I'll let you figure out if that's necessary.
3) You may have just simplified the codebase to get the concept across more cleanly (for which I applaud you if true), but just in case, I would encourage you to look at ways to modularize your work by building your file reading functionality as a function that is simply called with the file and string comparison information needed. (Also, probably an artifact of your snipping, but the "lone", "mile" and "Payne" references in there don't make sense; assuming those are the FSOs you are instantiating and have just forgotten to change them to fileA, fileB and fileC.)
Hope that helps a bit,
Bret
#bret
Someone else came through.
Here's a code that worked perfectly.
Would this be an example of "bubble sort"?
for k=23 to 0 Step-1
for j=0 to k
if (a(0,j)<a(0,j+1)) then
t1=a(0,j+1)
t2=a(1,j+1)
a(0,j+1)=a(0,j)
a(1,j+1)=a(1,j)
a(0,j)=t1
a(1,j)=t2
end If
next
next
for i=0 to 24
if a(0,i)>0 then
response.write (a(0,i)&a(1,i)&"<br>")
end if
next
set objFSO = Server.CreateObject("Scripting.FileSystemObject")
set objFolder = objFSO.GetFolder(server.mappath("Files"))
set objfiles = objFolder.Files
Function filesearch(name)
set searchname = objFSO.OpenTextFile(server.mappath(filename),1, true)
do until searchname.AtEndOfStream
lineData = lcase(searchname.ReadLine())
if instr(lineData,s)>0 then
instances = instances + 1
end if
Loop
End Function
For Each objFile in objFolder.Files
filesearch(objFile)
Response.Write filename & "<br>" & instances & "<br>" & "<br>"
Next
Set objFolder = Nothing
Set objFSO = Nothing
There are a few rough edges but what really bothers me now is the sorting. Where do I keep the bubble sort code?
EDIT:
I've got it work perfect with the following code.
For Each objFile in objFolder.Files
filesearch(objFile)
i = i + 1
a(0,i) = instances
a(1,i) = filename
Next
I was also wondering if there's anyway I could also write the total number of instances. I was able to do it before with:
for i=0 to 43
entries=entries+a(0,i)
next
I cant seem to make it work now.
EDIT:
Works now with:
for i = 0 to n
entries = entries + a(0,i)
next
I have declared a two dimensional array in the function library and associated it with a test. In action1 of the test, I tried to clear the array using "erase" statement.
My code -
In Function Library,
Dim strVerifyAry(25,6)
In action1,
erase strVerifyAry
Error message
Run Error - Type mismatch: 'Erase'
How to clear the contents of this array?
Works for me in plain VBScript, so it's most likely an issue with whatever engine QTP uses for running VBScript code. You should be able to emulate the behavior of Erase for a 2-dimensional array like this:
Sub EraseArray(ByRef arr)
For i = 0 To UBound(arr, 1)
For j = 0 To UBound(arr, 2)
If IsObject(arr(i, j)) Then
Set arr(i, j) = Nothing
Else
arr(i, j) = Empty
End If
Next
Next
End Sub
Or like this, if you don't want to set fields containing objects to Nothing:
Sub EraseArray(ByRef arr)
For i = 0 To UBound(arr, 1)
For j = 0 To UBound(arr, 2)
arr(i, j) = Empty
Next
Next
End Sub
I do not exactly understand why, but you can create a sub like
Public Sub DoErase (byRef Ary)
Erase Ary
End Sub
in the library, and call it from within the action like this:
DoErase StrVerifyAry
and that works.
Update: No it doesn't. The array is successfully passed to DoErase, and the DoErase call works fine, but the test afterwards still can reference the array elements that Erase was supposed to be erasing.
If the test declares the array, it works fine (Erase erases the elements).
This is very strange and probably has to do with the quirky scopes in function libraries.
Please let us know if you ever find out what's going on here...
This drove me nuts for an entire afternoon so I wanted to post an answer for future reference. I filled an array using the Split command and then needed to Erase it before the script looped back through the process again. Nothing I tried would erase or clear the array and the next use of Split just appended to the previous array elements.
By trying the 'array=Nothing' loop above, I finally managed to generate a "This array is fixed or locked" error which I researched. Turns out I had used the array in a 'For Each..Next' loop which locks the array so it can't be erased or cleared. More info is available HERE:
You can use a Dictionary collection rather than an array in some circumstances. Then use RemoveAll when you want to clear it. That doesn't help when your array was created by a split function, or whatever, but it can help in other use cases.
Set myDict = CreateObject("Scripting.Dictionary")
...
myDict.RemoveAll
Refer to: https://www.w3schools.com/asp/asp_ref_dictionary.asp
looper = (0..3).cycle
20.times { puts looper.next }
can I somehow find the next of 3? I mean if I can get .next of any particular element at any given time. Not just display loop that starts with the first element.
UPDATE
Of course I went though ruby doc before posting my question. But I did not find answer there ...
UPDATE2
input
looper = (0..max_cycle).cycle
max_cycle = variable that can be different every time the script runs
looper = variable that is always from interval (0..max_cycle) but the current value when the script starts could be any. It is based on Time.now.hour
output
I want to know .next value of looper at any time during the running time of the script
Your question is not very clear. Maybe you want something like this?
(current_value + 1) % (max_cycle + 1)
If, for example, max_cycle = 3 you will have the following output:
current_value returns
0 1
1 2
2 3
3 0
http://ruby-doc.org/core-1.9/classes/Enumerable.html#M003074