Generate first 10 numbers of a sequence - vbscript

I have been trying to create this sequence:
2,7,17,37,67,...
I have to print first 10 numbers of the series.
To do this, I have created the following:
option explicit
Dim m,n,i,str,d
m=2
d=10
n=7
For i=0 to 10
n=n+d
d=d+10
str=str&n&vbcrlf
msgbox str
next
I am unable to print first two numbers, 2 and 7, as they are declared before the for loop. Even if I store them in a variable called str, they get printed after every execution. Is there a way to add these two and print them only once.

You could add your initial value of m to your string before you start running your sequence. Then, append the value of n to your string at the start of your loop instead of the end so that you capture n's initial value. For example:
m=2: d=10: n=7
str = m & vbCrLf ' Capture initial value of m
For i = 1 to 9
str = str & n & vbCrLf ' Capture initial value of n
n = n + d
d = d + 10
Next
MsgBox str
Note that you're only looping 9 times now, since you've already captured the first number in your sequence (m) prior to your loop.
I also moved MsgBox outside your loop so that it only appears once, after the full 10-number sequence has been generated.

Related

Calculating average of numbers in a text file using VBScript

I am trying to calculate the average between all the numbers in a text file (every number is on a different line), no matter how many numbers there are. (Using VBScript)
Here is an example of the text file that I am trying to find the average between its numbers:
1
9
4
4
2
Also, sorry if I didn't word this well, it's my first question.
Can you try this script (I suppose that numbers are integer):
filename = "myfile.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.OpenTextFile(filename)
i = 0 'Elements number
sum = 0 'Sum of values
Do Until f.AtEndOfStream
sum = sum + CInt(trim(f.ReadLine))
i = i + 1
Loop
avg = sum / i 'Calculate the average
f.Close
Thank you

Multiplying 2 matrix using VBS

I would just like to know why this returns an "Expected end of statement" whenever I call the function multiply_matrix(matrixA, matrixB) and feed it with matrixA (3x3 matrix), and matrixB(3x3 matrix).
The error is always at "Next k".
This is the code of the function.
Function multiply_matrix(matrixA, matrixB)
dim answer_matrix(3,3)
for i=0 to UBound(matrixA,1)
for j=0 to UBound(matrixB,2)
sum = 0
for k=0 to UBound(matrixB,1)
sum = sum + ( matrixA(i,k) * matrixB(k,j) )
next k
answer_matrix(i,j) = sum
next j
next i
multiply_matrix = answer_matrix
End Function
Other Basic dialects allow variable names after the Next, VBScript doesn't.

Display tables between two numbers

I have been trying to create a VB script using the "Do While" loop in the VBScript. I want to generate tables between two numbers accepted from the user I don't know what's wrong with this:
option explicit
Dim i, a, j, product, table
a = inputbox("enter a number")
For i=1 to a
j=1
Do while(j<=10)
product=i*j
a=i&"*"&j&"="&product
table=table&vbnewline&a
loop
msgbox table
next
The above results in a blank window.
Can anyone help me resolve the problem?
P.S.
I managed to get it to work using the "For" loop.
Option 1: Use a For loop:
Dim i
For i = 1 To 10
' This will run 10 times
Next
Option 2: Use a Do While loop:
Dim j
j = 1
Do While j <= 10
' This will also run 10 times
j = j + 1
Loop
Edit:
If you need to loop on both i and j, you can create a nested For loop:
Dim i, j
For i = 1 To 10
For j = 1 To 10
' This will run 10 times for each value of i (so 100 total)
Next
Next

Combining two lists with minimum distance between elements

I have to lists like these:
a = ["1a","2a","3a","4a","5a","6a","7a","8a","9a","10a","11a","12a","13a","14a"]
b = ["1b","2b","3b","4b","5b","6b","7b","8b","9b","10b","11b","12b","13b","14b"]
And what I want is to combine them, so that there is at least a difference of n elements between an element from a and it's corresponding element in b.
As an example, if my n is 10, and "3a" is in position 3 and "3b" is in position 5, that isn't a solution since there's only a distance of 2 between these corresponding elements.
I have already solved this for the purpose I want through a brute force method: shuffle the union of the two arrays and see if the constraint is met; if not, shuffle again and so on... Needless to say, that for 14 elements array, sometimes there is 5 to 10 second computation to yield a solution with a minimum distance of 10. Even though that's kind of ok for what I am looking for, I am curious about how I could solve this in a more optimized way.
I am currently using Python, but code in any language (or pseudo-code) is more than welcomed.
EDIT: The context of this problem is something like a questionnarie, in which around 100 participants are expected to join in. Therefore, I am not necessarily interested in all the solutions, but rather something like the first 100.
Thanks.
For your specific scenario, you could use a randomized approach -- though not as random as what you've already tried. Something like this:
start with a random permutation of the items in both lists
create a new permutation by creating a copy of the other and randomly swapping two items
measure the quality of the permutations, e.g., the sum of the distances of each pair of related items, or the minimum of such distances
if the quality of the new permutation is better than that of the original permutation, keep the new one, otherwise discard the new one and continue with the original permutation
repeat from 2. until each distance is at least 10 or until quality does not improve over a number of iterations
The difference to shuffling the whole list in each iteration (as in your approach) is that in each iteration the permutation can only get better, until a satisfying solution is found.
Each time you run this algorithm, the result will be slightly different, so you can run it 100 times for 100 different solutions. Of course, this algorithm does not guarantee to find a solution (much less all such solutions), but it should be fast enough so that you could just restart it in case it fails.
In Python, this could look somewhat like this (slightly simplified, but still working):
def shuffle(A, B):
# original positions, i.e. types of questions
kind = dict([(item, i) for i, item in list(enumerate(A)) + list(enumerate(B))])
# get positions of elements of kinds, and return sum of their distances
def quality(perm):
pos = dict([(kind[item], i) for i, item in enumerate(perm)])
return sum(abs(pos[kind[item]] - i) for i, item in enumerate(perm))
# initial permutation and quality
current = A + B
random.shuffle(current)
best = quality(current)
# improve upon initial permutation by randomly swapping items
for g in range(1000):
i = random.randint(0, len(current)-1)
j = random.randint(0, len(current)-1)
copy = current[:]
copy[i], copy[j] = copy[j], copy[i]
q = quality(copy)
if q > best:
current, best = copy, q
return current
Example output for print shuffle(a, b):
['14b', '2a', '13b', '3a', '9b', '4a', '6a', '1a', '8a', '5b', '12b', '11a', '10b', '7b', '4b', '11b', '5a', '7a', '8b', '12a', '13a', '14a', '1b', '2b', '3b', '6b', '10a', '9a']
As I understand from your question, it is possible to perform all the ordering by relying exclusively on the indices of the arrays (i.e., on pure integers) and thus the problem can be reduced to create (valid) ranges instead of analysing each element.
for each a <= total_items-n , valid b = if(a + n == total_items){total_items} else{[a + n, total_items]}
For example:
n = 10;
total_items = 15;
for a = 1 -> valid b = [11, 15]
for a = 2 -> valid b = [12, 15]
, etc.
This would be perfomed 4 times: forwards and backwards for a respect to b and the same for b respect to a.
In this way you would reduce the number of iterations to its minimum expression and would get, as an output, a set of "solutions" for each position, rather than a one-to-one binding (that is what you have right now, isn't it?).
If there are equivalents in Python to .NET's Lists and LINQ, then you may be able to directly convert the following code. It generates up to 100 lists really quickly: I press "debug" to run it and up pops a windows with the results in much less than a second.
' VS2012
Option Infer On
Module Module1
Dim minDistance As Integer = 10
Dim rand As New Random ' a random number generator
Function OkToAppend(current As List(Of Integer), x As Integer) As Boolean
' see if the previous minDistance values contain the number x
Return Not (current.Skip(current.Count - minDistance).Take(minDistance).Contains(x))
End Function
Function GenerateList() As List(Of String)
' We don't need to start with strings: integers will make it faster.
' The "a" and "b" suffixes can be sprinkled on at random once the
' list is created.
Dim numbersToUse() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
Dim pool As New List(Of Integer)
' we need all the numbers twice
pool.AddRange(numbersToUse)
pool.AddRange(numbersToUse)
Dim newList As New List(Of Integer)
Dim pos As Integer
For i = 0 To pool.Count - 1
' limit the effort it puts in
Dim sanity As Integer = pool.Count * 10
Do
pos = rand.Next(0, pool.Count)
sanity -= 1
Loop Until OkToAppend(newList, pool(pos)) OrElse sanity = 0
If sanity > 0 Then ' it worked
' append the value to the list
newList.Add(pool(pos))
' remove the value which has been used
pool.RemoveAt(pos)
Else ' give up on this arrangement
Return Nothing
End If
Next
' Create the final list with "a" and "b" stuck on each value.
Dim stringList As New List(Of String)
Dim usedA(numbersToUse.Length) As Boolean
Dim usedB(numbersToUse.Length) As Boolean
For i = 0 To newList.Count - 1
Dim z = newList(i)
Dim suffix As String = ""
If usedA(z) Then
suffix = "b"
ElseIf usedB(z) Then
suffix = "a"
End If
' rand.Next(2) generates an integer in the range [0,2)
If suffix.Length = 0 Then suffix = If(rand.Next(2) = 1, "a", "b")
If suffix = "a" Then
usedA(z) = True
Else
usedB(z) = True
End If
stringList.Add(z.ToString & suffix)
Next
Return stringList
End Function
Sub Main()
Dim arrangements As New List(Of List(Of String))
For i = 1 To 100
Dim thisArrangement = GenerateList()
If thisArrangement IsNot Nothing Then
arrangements.Add(thisArrangement)
End If
Next
'TODO: remove duplicate entries and generate more to make it up to
' the required quantity.
For Each a In arrangements
' outputs the elements of a with ", " as a separator
Console.WriteLine(String.Join(", ", a))
Next
' wait for user to press enter
Console.ReadLine()
End Sub
End Module

How to get values in reverse with loops

The issue is with the bottom of my code where I have to get the program to recite the entered values in reverse order. I think it might be something to do with the index?
Option Explicit On
Option Strict On
'Author: Murray Spears
'Date: October 12th 2012
'Write a program that accepts five input values and stores them into an array.
'Then display numbers in reverse order.
'Then display the average number, and all numbers that are are above average.
Imports System
Module Values
Sub Main()
Dim Number(4) as Integer
Dim Average as Double = 0
Dim Index as integer
'
For Index = 0 to 4
Console.Write("Enter number: ")
Number(Index)=Convert.ToInt32(Console.Readline())
Next Index
'Figure out the average for all the entered values.
Average = (Number(0)+Number(1)+Number(2)+Number(3)+Number(4))/5
Console.Writeline("The average of the numbers is: " &Average)
Console.Write("Numbers that are greater than the average: ")
Index = 4
Do until Index = 0
If Number(Index) > Average then
Console.Writeline(Number(Index))
End If
Index -=1
Loop
Console.Writeline("Numbers in reverse order: ")
Index = 4
Do while Number(index) > 0
Console.Writeline(Number(Index))
Number(index) -= 1
Loop
End Sub
End Module
Use Step -1 to step backwards.
For Index = 4 To 0 Step -1
' do your thing
Next
Imo, the simplest way is to just use a loop as you did when you entered the numbers but as you wrote yourself make the indexes go in reverse.
This is what the "Step -1" is for.
For Index As Integer = 4 To 0 Step -1
Console.Writeline(Number(Index))
Next

Resources