mode, mean, average etc calculator, out of range error? - vbscript

I get the error:
Line: 23
Char: 4
Subscript out of range: 'numbers'
which is at: if numbers(i) = a then
I have made this in javascript and it works, but I need to convert it.
function info(numbers)
dim numbers2(99999)
numbers3 = ""
dim low
dim high
dim mean
dim halve
total = 0
dim spaces(99999)
dim a
dim b
dim i
dim c
dim whole
dim meadian
dim mode1
dim mode2
dim intResult
dim med
x = UBound(numbers)+1
For a=0 To 999999 Step 1
For i=0 To x Step 1
if numbers(i) = a then
c = numbers(i)
numbers2 = c
numbers3 = numbers3 + c + " "
low = numbers2(0)
high = a
total = total + c
end if
Next
Next
halve = UBound(numbers2)/2
whole = UBound(numbers2)
intResult = whole Mod 2
If intResult = 0 Then
halve = halve - 0.5
median = numbers2(halve)
med = true
Else
median = (numbers2(halve1)+numbers2(halve1-1))/2
med = false
End if
mean = total / UBound(numbers)
if med = true then
msgbox(numbers3 & chr(13) & chr(13) & "Lowest: " & low & chr(13) & "Highest: " & high & chr(13) & "Total: " & total & chr(13) & "Median: " & median & chr(13))
else
msgbox(numbers3 & chr(13) & chr(13) & "Lowest: " & low & chr(13) & "Highest: " & high & chr(13) & "Total: " & total & chr(13) & "Median: " & median & " -" & numbers2(halve1) & "x" & numbers2(halve1-1) & chr(13))
end if
end function
dim q(19,291,29)
info(q)
And also, how can I be able to put q in inside a inputbox?
Just ask if you want the javascript code.

If you're going to declare your variables (good idea for production code): use Option Explicit and declare all variables. Otherwise don't bother.
Variable declarations become a little more readable if you put them on one line (comma-separated):
Dim numbers2(99999), numbers3, low, high, mean, halve, total
Dim spaces(99999), ...
...
numbers3 = ""
total = 0
As #RogerRowland has mentioned, the line x = UBound(numbers)+1 will return an index 1 greater than the upper boundary of your array, so the loop
For i=0 To x Step 1
if numbers(i) = a then
...
end if
Next
will try to access an element outside the array in the last loop cycle. Better do it like this:
For i=0 To UBound(numbers)
If numbers(i) = a Then
...
End If
Next
Step 1 is the default, BTW, so it can be omitted.
The Type Mismatch error you got after fixing that is most likely because you declared numbers2 as a static array:
dim numbers2(99999)
but then assign a scalar to it inside the loop:
numbers2 = c
That line should probably be
numbers2(i) = c

Related

Split int array in to two arrays even and odd VBscript error

I have written code for an array of numbers which prints out. I'm now writing code to split the array into even and off numbers. I've started off with an if statement to separate the numbers but i'm struggling to find a solution on how to do it. My code below is failing as it's unable to split the numbers.
Sub main()
a=Array(5,10,15,20)
for each x in a
Msgbox(x)
If MyArray(I) / 2 = MyArray(I)
List1.AddItem MyArray(I) ' Even Integers
Else
List2.AddItem MyArray(I) ' Odd Integers
End if
next
End Sub
As Lankymart suggests, the simplest approach would be to use Mod() and check if the remainder is 1 or 0, but you can also do it with the approach you seemed to be working towards:
If MyArray(index)/2 = Int(MyArray(index)/2) Then
' Even number
Else
' Odd number
End If
Mod() approach:
If MyArray(index) Mod 2 = 0 Then
' Even number
Else
' Odd number
End If
Here's a complete subroutine that demonstrates what you are trying to do:
Dim arr(4) As Integer
Dim arrEven() As Integer
Dim iEvenValues As Integer
Dim arrOdd() As Integer
Dim iOddValues As Integer
Dim iCounter As Integer
' Initialize array
arr(0) = 5
arr(1) = 10
arr(2) = 15
arr(3) = 20
For iCounter = 1 To UBound(arr)
If arr(iCounter - 1) Mod 2 = 0 Then
iEvenValues = iEvenValues + 1
ReDim Preserve arrEven(iEvenValues)
arrEven(iEvenValues - 1) = arr(iCounter - 1)
Else
iOddValues = iOddValues + 1
ReDim Preserve arrOdd(iOddValues)
arrOdd(iOddValues - 1) = arr(iCounter - 1)
End If
Next
Dim sValues As String
sValues = "Even values (" & iEvenValues & "):"
For iCounter = 1 To UBound(arrEven)
sValues = sValues & " " & arrEven(iCounter - 1)
Next
MsgBox sValues
sValues = "Odd values (" & iOddValues & "):"
For iCounter = 1 To UBound(arrOdd)
sValues = sValues & " " & arrOdd(iCounter - 1)
Next
MsgBox sValues

vbscript divide files into four groups

I am developing a script to divide the number of files in a folder into four groups. These will be turned into four batch files but for now the issue is dividing them up as evenly as possible.
The script below will work somewhat - if I have a Count that will be divided by 4 evenly but if I have an odd number, no go and less than four will crash. You can run the script just replace the "C:\1_SourceData\Section_16\" with your own path of files. If you un-comment the section 'Add remainder to front', it was to thow any extra files, like an odd number, to the first batch but that does not quite work. The number of files in the folder will range from 1 to 25.
Any help would be most appreciated.
Option Explicit
Dim fileList : Set fileList = GetFileList("C:\1_SourceData\Section_16\")
Dim NumOfFiles : NumOfFiles = fileList.Count - 1
Dim modNumber : modNumber = NumOfFiles/4
Dim remainder : remainder = NumOfFiles Mod modNumber
Dim string1 : string1 = "batch" & batchCounter
Dim string2 : string2 = ""
'Add remainder to front
'Dim i : i = 0
'For i = NumOfFiles - remainder To NumOfFiles
' string2 = string2 & vbTab & fileList(i) & vbNewLine
'Next
Dim batchCounter : batchCounter = 1
Dim file
Dim j : j = 0
For Each file In fileList
string2 = string2 & vbTab & file & vbNewLine
j = j + 1
If j Mod modNumber = 0 Then
WScript.Echo string1 & vbNewLine & string2
batchCounter = batchCounter + 1
string1 = "batch" & batchCounter
string2 = ""
End If
Next
Public Function GetFileList(path)
Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim fileList : Set fileList = CreateObject("System.Collections.ArrayList")
Dim InfFolder : Set InfFolder = objFSO.GetFolder(path)
Dim File
For Each File In objFSO.GetFolder(path).Files
fileList.Add File
Next Set GetFileList = fileList
End Function
The problem is: the .Files collection is accessible via For Each only. A 'distribution by number' (think modulo) needs an extra counter. Demo script:
Option Explicit
ReDim a(3) ' 4 groups/collections
Dim i
For i = 0 To UBound(a)
Set a(i) = CreateObject("System.Collections.ArrayList")
Next
i = 0
Dim f
' fake a list of elms accessible via For Each only
For Each f In Split("a b c d e f g h i j k l m n")
a(i Mod 4).Add f ' use Mod to determine the 'bucket'
i = i + 1 ' counter needed for Mod
Next
For i = 0 To UBound(a)
WScript.Echo i, Join(a(i).ToArray())
Next
output:
cscript 40639293.vbs
0 a e i m
1 b f j n
2 c g k
3 d h l
You could structure your loop differently.
There are F files that should be devided into B batches of X files each. Two things can happen:
F is an exact multiple of B, in which case X = F / B
F is not an exact multiple of B, in which case X = (F / B) + 1
Therefore we can write two loops that (together) count from 1 to F:
Option Explicit
Const BATCHES = 4
Const PATH = "C:\1_SourceData\Section_16"
Dim FSO : Set FSO = CreateObject("Scripting.FileSystemObject")
Dim fileList : Set fileList = GetFileList(PATH)
Dim b, i, f, x
f = fileList.Count
x = CInt(f / BATCHES)
If x * BATCHES < f Then x = x + 1
For b = 0 To BATCHES - 1
If (b * x < f) Then WScript.Echo "batch" & (b + 1)
For i = b * x To (b + 1) * x - 1
If (i < f) Then WScript.Echo vbTab & fileList(i)
Next
Next
Function GetFileList(path)
Dim file
Set GetFileList = CreateObject("System.Collections.ArrayList")
For Each file In FSO.GetFolder(path).Files
GetFileList.Add File
Next
End Function

How to convert a string string of key-value pairs into an array

I have below sample data. I want to convert this string into an array
device_name="Text Data" d_id=7454579598 status="Active" Key=947-4378-43248274
I tried below:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
("d:\vbfile.txt", ForReading)
Do Until objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
arrServiceList = Split(strNextLine , " ")
For i = 0 to Ubound(arrServiceList)
Wscript.Echo arrServiceList(i)
Next
Loop
it generates below
device_name="Text
Data"
d_id=7454579598
status="Active"
Key=947-4378-43248274
Expected output
device_name="Text Data"
d_id=7454579598
status="Active"
Key=947-4378-43248274
How about this approach:
Option Explicit
Const ForReading = 1
Dim FSO, keyValueExpr
Set FSO = CreateObject("Scripting.FileSystemObject")
Set keyValueExpr = New RegExp
keyValueExpr.Pattern = "\b(\w+)=(""[^""]*""|\S*)"
keyValueExpr.Global = True
Dim result, record, match
Set result = CreateObject("Scripting.Dictionary")
With FSO.OpenTextFile("D:\vbfile.txt", ForReading)
While Not .AtEndOfStream
Set record = CreateObject("Scripting.Dictionary")
result.Add result.Count + 1, record
For Each match In keyValueExpr.Execute(.ReadLine)
record.Add match.SubMatches(0), match.SubMatches(1)
Next
Wend
.Close
End With
Dim msg, lineNo, key
For Each lineNo In result
msg = "Line " & lineNo & vbNewLine
For Each key In result(lineNo)
msg = msg & vbNewLine & key & ": " & result(lineNo)(key)
Next
MsgBox msg
Next
It uses a regular expression that can identify key-value pairs that fulfill these conditions:
The key is a string of characters (a-z), digits (0-9) or underscores (_)
The value is anything that is either enclosed in double quotes or anything except a space.
Compare https://regex101.com/r/zL2mX5/1
The program creates nested dictionaries, the outer dictionary holding all lines of the file with the corresponding line numbers (1..n) for keys, each inner dictionary holds the key-value pairs found on each line.
This layout gives you the opportunity to address every value very conveniently:
value = result(3)("status")
Here is a function that might help. It takes a string and a delimiter and returns an array obtained by splitting on the delimiter -- whenever the delimiter isn't inside a quote:
Function SmartSplit(s, d)
Dim c, i, j, k, n, A, quoted
n = Len(s)
ReDim A(n - 1)
quoted = False
i = 1
k = 0
For j = 1 To n
c = Mid(s, j, 1)
If c = """" Then quoted = Not quoted
If c = d And Not quoted Then
A(k) = Mid(s, i, j - i)
k = k + 1
i = j + 1
End If
Next
If i < n Then
A(k) = Mid(s, i)
Else
k = k - 1
End If
ReDim Preserve A(k)
SmartSplit = A
End Function
In your example -- just replace Split by SmartSplit and it should work.

Convert Hex to String using VbScript

here is a script which convert string into hex code:
strString = "test"
strHex =""
For i=1 To Len(strString)
strHex = strHex & " " & Hex(Asc(Mid(strString,i,1)))
Next
strHex = Right(strHex,Len(strHex)-1)
WScript.Echo strHex
I want to do a reverse action which converts hex into string, is this possible using vbscript?
VBScript uses "&H" to mark numbers as hexadecimals. So
>> WScript.Echo Chr("&H" & "41")
>>
A
>>
demonstrates the strategy in principle. Demo code:
Option Explicit
Function s2a(s)
ReDim a(Len(s) - 1)
Dim i
For i = 0 To UBound(a)
a(i) = Mid(s, i + 1, 1)
Next
s2a = a
End Function
Function s2h(s)
Dim a : a = s2a(s)
Dim i
For i = 0 To UBound(a)
a(i) = Right(00 & Hex(Asc(a(i))), 2)
Next
s2h = Join(a)
End Function
Function h2s(h)
Dim a : a = Split(h)
Dim i
For i = 0 To UBound(a)
a(i) = Chr("&H" & a(i))
Next
h2s = Join(a, "")
End Function
Dim s : s = "test"
WScript.Echo 0, s
WScript.Echo 1, s2h(s)
WScript.Echo 2, h2s(s2h(s))
output:
0 test
1 74 65 73 74
2 test
Update wrt comment/unicode:
Use AscW/ChrW (VB ref) to deal with UTF 16.
Option Explicit
Function s2a(s)
ReDim a(Len(s) - 1)
Dim i
For i = 0 To UBound(a)
a(i) = Mid(s, i + 1, 1)
Next
s2a = a
End Function
Function s2h(s)
Dim a : a = s2a(s)
Dim i
For i = 0 To UBound(a)
a(i) = Right("0000" & Hex(AscW(a(i))), 4)
Next
s2h = Join(a)
End Function
Function h2s(h)
Dim a : a = Split(h)
Dim i
For i = 0 To UBound(a)
a(i) = ChrW("&H" & a(i))
Next
h2s = Join(a, "")
End Function
Dim s : s = "abcä" & ChrW("&H" & "d98a")
WScript.Echo 0, s
WScript.Echo 1, s2h(s)
WScript.Echo 2, h2s(s2h(s))

How to create multi-dimensional jagged arrays in VbScript?

I need to create multi-dimensional array of strings. Each row of the array can have varying number of strings. Something like the follwing code:
twoDimension = Array(Array())
ReDim Preserve twoDimension(3)
For i = 0 to 2
If i = 1 Then
twoDimension(i) = Array(1,2,3)
End If
If i = 2Then
twoDimension(i) = Array(1,2,3,4,5)
End If
Next
How about a dictionary
Set a = CreateObject("Scripting.Dictionary")
a.Add 0, Array(1,2,3)
a.Add 1, Array(4,5,6)
MsgBox a.Count
MsgBox a.Item(0)(2)
MsgBox a.Item(1)(1)
There's nothing wrong with having jagged arrays in VBScript. There are some minor issues with your code (ReDim to 3 but only assigning values to 2, unnecessarily using a For loop to assign values), but in general, that's the correct syntax to use.
Option Explicit
Dim twoDimension, i, j
twoDimension = Array(Array())
ReDim Preserve twoDimension(2)
twoDimension(1) = Array(1,2,3)
twoDimension(2) = Array(1,2,3,4,5)
For i = 0 To UBound(twoDimension)
For j = 0 To UBound(twoDimension(i))
WScript.Echo "(" & i & "," & j & ") = " & twoDimension(i)(j)
Next
Next

Resources