I have written code which generates a random number between 1-9.
I now want to add to this and generate a random number but generate a new number if that number has already been used before.
Sub main()
Dim max,min
max=9
min=1
Randomize
MsgBox(Int((max-min+1)*Rnd+min))
// Random number between 1-9 is generated
I had tried to implement a loop but i'm unsure of how it would work as i would need to keep the number generated in memory
If Int = random
Msgbox("Already in use")
End If
If Int = not random Then
Msgbox("Can be used")
End If
End Sub
Sounds like you just want to keep track of which random numbers have already been chosen. You could handle this any number of different ways (eg, with an array, hash-table/dictionary, numeric bit mask, etc.)
The solution I present below is similar to a numeric bit mask, but uses a string. Starting at all zeros (eg, "0000"), each indexable position in the string gets populated with a one (1) until the string becomes all ones (eg, "1111"). While potentially oversimplified -- since it assumes your min will always be one (1) -- it should get you started.
Dim min : min=1
Dim max : max=9
Dim result : result = ""
Dim r, s: s = String(max, "0")
Randomize
Do
r = Int((max-min+1)*Rnd+min)
If "0" = Mid(s, r, 1) Then
WScript.Echo "Can be used: " & r
result = result & ":" & r
s = Left(s, r-1) & "1" & Right(s, max-r)
Else
WScript.Echo "Already in use: " & r
End If
Loop Until String(max, "1") = s
WScript.Echo "Result" & result
Sample output:
Can be used: 4
Can be used: 5
Can be used: 9
Can be used: 3
Already in use: 3
Can be used: 1
Can be used: 8
Can be used: 6
Already in use: 6
Can be used: 7
Already in use: 8
Already in use: 4
Already in use: 3
Already in use: 1
Already in use: 6
Can be used: 2
Result:4:5:9:3:1:8:6:7:2
Hope this helps.
Related
I have 4 variables which they contain some values.
I have already convert them in numbers with CDbl.
So I have something like that:
var1=CDbl(str1)
var2=CDbl(str2)
var3=CDbl(str3)
var4=CDbl(str4)
How can I find the smallest number between var1, var2, var3 and var4?
The following works. You just have to pass the values as an array.
Function FindSmallest(arr)
out = arr(0)
For i = 1 to UBound(arr)
If out > arr(i) Then
out = arr(i)
End If
Next
FindSmallest = out
End Function
WScript.Echo FindSmallest(Array(var1,var2,var3,var4))
Upon trying to run my code I get the error "compile error: variable not defined" and it highlights my Sub line. Here is the code for reference.
Sub RI_Processing()
Dim i As Single
Dim Output() As Single 'Define this dynamic array for the solver output
Process the DMSO data
For i = 1 To 45 Step 1
Workbooks("Calibration Range 1 Normalized Profiles.xlsx").Activate
RawData.Range("C10:C649") = Sheet1.Columns("i").Values
SolverOk SetCell:="$E$7", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$2:$B$4", _
Engine:=1, EngineDesc:="GRG Nonlinear"
SolverSolve
Workbooks("Simulated Fresnel Function.xlsx").Activate
Output(i, 1) = Sheet1.Range("B4").Values
Next i
i = 0
' Process the NaCl Data
For i = 1 To 102 Step 1
Workbooks("Calibration Range 1 Normalized Profiles.xlsx").Activate
RawData.Range("C10:C649") = Sheet2.Columns("i").Values
SolverOk SetCell:="$E$7", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$2:$B$4", _
Engine:=1, EngineDesc:="GRG Nonlinear"
SolverSolve
Workbooks("Simulated Fresnel Function.xlsx").Activate
Output(i, 2) = Sheet1.Range("B4").Values
Next i
i = 0
' Process the Sucrose data
For i = 1 To 72 Step 1
Workbooks("Calibration Range 1 Normalized Profiles.xlsx").Activate
RawData.Range("C10:C649") = Sheet3.Columns("i").Values 'Copies the data of all 'i' columns to raw data for solver
SolverOk SetCell:="$E$7", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$2:$B$4", _
Engine:=1, EngineDesc:="GRG Nonlinear"
SolverSolve 'Run solver
Workbooks("Simulated Fresnel Function.xlsx").Activate
Output(i, 3) = Sheet1.Range("B4").Values 'Put solver output to the matrix 'output' in the appropriate columns
Next i
End Sub
I'm not entirely sure what I'm doing wrong here. I have tested the code by input and output and it functions as desired no pun intended. :'P
I'm just not setting up this function correctly and I believe it's because my arguments happen to be desirably a string. Where if done correctly "CD" will be inserted into the middle of "ABEF". So, how do I go about doing this?
Thanks!
insertstr(ABEF, CD)
Function insertstr(string1, string2)
nostrmsg = "No string"
fullng = len(string1)
half = len(string1)/2
if half>0 then hfstr1 = mid(string1, 1, half)
str2lng = len(string2)
if str2lng>0 then paste = hfstr1+string2
lshalf = mid(string1, half+1, fullng)
if str2lng+half=str2lng+half then insert = paste+lshalf
End Function
Start with the knowledge that a functions returns a value, a tentative specification of what the function should do, and a basic testing skeleton:
Option Explicit
' returns the string build by inserting m(iddle) into f(ull) at half position
Function insertInto(f, m)
insertInto = "?"
End Function
Dim t, r
For Each t In Array( _
Array("ABEF", "CD", "ABCDEF") _
)
r = insertInto(t(0), t(1))
WScript.Echo t(0), t(1), r, CStr(r = t(2))
Next
output:
cscript 26873276.vbs
ABEF CD ? False
Then learn about Left, Mid, Len, and \ (integer division).
At last, re-write insertInto() so that the result starts with
cscript 26873276.vbs
ABEF CD ABCDEF True
I would like to know if the performance is better in case I am storing the string length
in a temporary variable when I am using a loop of at list 10,000 loops instead of calculating it in every loop?
Code example calculating the string length:
'--
Dim I
Dim str : str = "Lets say this string length is around 50,000"
'--
For I=0 To 100000
Response.Write Len(str) & "<br>"
Next
Code example using a temporary variable:
'--
Dim I
Dim str : str = "Lets say this string length is around 50,000"
Dim temp : temp = Len(str)
'--
For I=0 To 100000
Response.Write temp & "<br>"
Next
What do you think is better?
Thanks!
Here's an idea: Why don't you just measure it?
Dim start: start = Timer
...<code here>...
Response.Write FormatNumber(Timer - start, 8)
To measure is to know. Having said that: You might want to read the story about Shlemiel the Painter.
Eventually the Response.write will probably be the most expensive operation; if you really want to measure the "cost" of Len() vs. a temp variable (even though both methods output the same amount of data) you should probably do something like this:
Dim I, J, X
Dim start
Dim str : str = String(50000, "-")
Dim tmp : tmp = Len(str)
Response.Write "Temp var:<br>"
For J = 0 to 10
start = Timer
X = 0
For I=0 To 100000
x = x + tmp
Next
Response.write FormatNumber(Timer - start,8) & "<br>"
Next
Response.Write "Len:<br>"
For J = 0 to 10
start = Timer
X = 0
For I=0 To 100000
x = x + Len(str)
Next
Response.write FormatNumber(Timer - start,8) & "<br>"
Next
In my case, the output is:
Temp var:
0,03125000
0,03125000
0,04687500
0,03125000
0,03515625
0,02734375
0,03125000
0,03125000
0,03515625
0,02734375
0,03125000
Len:
0,04687500
0,04687500
0,03125000
0,04687500
0,04687500
0,04687500
0,05078125
0,02734375
0,04687500
0,05078125
0,04687500
As you can see, using Len() every iteration is measureably slower (even though it isn't that much, about 35%). Using a temp-variable will be a good idea, but you could've guessed that without this knowledge or measuring at all, didn't you?
I am unsure about VBScript but many languages (and their compilers/JIT'ers) do optimize this stuff at compile/JIT-time on their own. The compiler/runtime/JIT usually "notices" these kinds of patterns and will introduce a "temp variable" automatically.
But then: why would you be doing tens-of-thousands of iterations on such a large chunk of data in (classic) ASP at all? Do you really have to output this much data? Can't the processing be done (more) by the backend or something? Are you doing actually 10.000 iterations on 50Kb strings? Or is this just a theoretical discussion? If you're doing one, or a handful, iterations, on "simple, short strings" I wouldn't bother with an extra variable at all. This introduces other issues; for example having to keep the variable "in sync" should the str variable change etc. Also readability (and "understandability) would be improved just using Len(foo) where you need the length. If you do introduce a variable, which is justified and sometimes an optimization worth the "hassle", I would at least make sure it is named correctly (not tmp but foolength for example).
If you just follow the simple rule "Never do in a loop what you can do before it" you don't have to waste time on benchmarks.
(It's bitter to have to read such a question, and I want to batter a programmer who does not know on which side the toast is buttered.)
I've got some big (let's say 200 MiB - 2 GiB) textual files filled with tons of duplicated records. Each line can have about 100 or even more exact duplicates spread over the file. The task is to remove all the repetitions, leaving one unique instance of every record.
I've implemented it as follows:
object CleanFile {
def apply(s: String, t: String) {
import java.io.{PrintWriter, FileWriter, BufferedReader, FileReader}
println("Reading " + s + "...")
var linesRead = 0
val lines = new scala.collection.mutable.ArrayBuffer[String]()
val fr = new FileReader(s)
val br = new BufferedReader(fr)
var rl = ""
while (rl != null) {
rl = br.readLine()
if (!lines.contains(rl))
lines += rl
linesRead += 1
if (linesRead > 0 && linesRead % 100000 == 0)
println(linesRead + " lines read, " + lines.length + " unique found.")
}
br.close()
fr.close()
println(linesRead + " lines read, " + lines.length + " unique found.")
println("Writing " + t + "...")
val fw = new FileWriter(t);
val pw = new PrintWriter(fw);
lines.foreach(line => pw.println(line))
pw.close()
fw.close()
}
}
And it takes ~15 minutes (on my Core 2 Duo with 4 GB RAM) to process a 92 MiB file. While the following command:
awk '!seen[$0]++' filename
Takes about a minute to process 1.1 GiB file (which would take many hours with the above code of mine).
What's wrong with my code?
What is wrong is that you're using an array to store the lines. Lookup (lines.contains) takes O(n) in an array, so the whole thing runs in O(n²) time. By contrast, the Awk solution uses a hashtable, meaning O(1) lookup and a total running time of O(n).
Try using a mutable.HashSet instead.
You could also just read all lines and call .distinct on them. I don't know how distinct is implemented, but I'm betting it uses a HashSet to do it.