Discussion:
VbScript and .NET objects
(too old to reply)
Reventlov
2015-08-29 12:40:50 UTC
Permalink
I googled a while looking for new Active/x objects that can be instanced from VbScript.
Most of the .NET objects seem to be in DLLs that can be called with other methods but not
with CreateObject or whatever vb.net uses to connect to its objects.
I have found these examples:
Some sort of Dictionary with sorting, search, remove, insert.
A string builder with inser/replace methods
A LIFO and a FIFO stack
Any others?



Set DataList = CreateObject ("System.Collections.ArrayList")
DataList.Add "B"
DataList.Add "C"
DataList.Add "E"
DataList.Add "D"
DataList.Add "A"

DataList.Sort()
'Datalist.Reverse() 'Reverse order
'DataList.Remove("D") 'Removes an element

For Each strItem in DataList
Wscript.Echo strItem
Next

'*******************************************************************************

'Random number between 1 and 100 (1 included, 100 aparently not included)
Set objRandom = CreateObject("System.Random")
Wscript.Echo objRandom.Next_2(1,100)

'*******************************************************************************

'Concatenate strings. Faster than using "&"
set wrt = CreateObject("System.IO.StringWriter")
for i = 1 to 100000
s = CStr(i)
wrt.Write_12 s 'String. Write_11 for decimal, _10 for double, _9 for float
next
s = wrt.GetStringBuilder().ToString()

'*******************************************************************************

set sb = CreateObject("System.Text.StringBuilder")
sb.AppendFormat_5 Nothing, "{0} is a {1} number" & vbCrLf, Array(1, "loneliest")
sb.AppendFormat_5 Nothing, "{0} is a {1} number" & vbCrLf, Array(2, "happiest")
WScript.Echo sb.ToString()
'Prints:
'1 is a loneliest number
'2 is a happiest number

'*******************************************************************************

Set s = CreateObject("System.Text.StringBuilder")
s.Append_3 "I love deadlines. I like the whooshing sound they make as they fly by."
s.Append_3 "and the rest."
wscript.echo s.Length
wscript.echo s.Capacity
wscript.echo chr(s.chars(0)) 'returns first char
wscript.echo s.Replace("t", "d").Replace("l", "k").toString
s.Insert_2 7, "insert this " 'after char 7, starting from 1
WScript.Echo s.tostring()
WScript.Echo s.remove(10,4).tostring() 'Removes 4 chars starting from position 10
WScript.Echo s.tostring()
s.clear 'Removes all characters from the stringbuilder instance

'*******************************************************************************
'A sorted dictionary object
'http://www.reliance-scada.com/en/support/articles/technical/vbscript-tip-working-with-an-object-list
Dim Message, SortedList, i, s

' Initializes the message.
Message = ""

' Creates a list.
Set SortedList = CreateObject("System.Collections.SortedList")

' Fills the list.
SortedList.Add "Point", 1
SortedList.Add "Point Cloud", 2
SortedList.Add "Curve", 4
SortedList.Add "Surface", 8
SortedList.Add "Polysurface", 16
SortedList.Add "Mesh", 32

' Returns the element count.
Message = Message & "1: " & SortedList.Count & vbCrLf

' Returns the value by key.
Message = Message & "2: " & SortedList("Surface") & vbCrLf

' Returns the value at the index.
s = ""
For i = 0 To SortedList.Count - 1
s = s & CStr(SortedList.GetByIndex(i)) & " "
Next
Message = Message & "3: " & s & vbCrLf

' Verifies the existence of the key.
Message = Message & "4: " & SortedList.ContainsKey("Polysurface") & vbCrLf

' Verifies the existence of the value.
Message = Message & "5: " & SortedList.ContainsValue(16) & vbCrLf

' Returns the index of the key (searches for the element by key).
Message = Message & "6: " & SortedList.IndexOfKey("Polysurface") & vbCrLf

' Returns the index of the value (searches for the element by value).
Message = Message & "7: " & SortedList.IndexOfValue(16) & vbCrLf

' Removes the element by key.
SortedList.Remove "Polysurface" & vbCrLf

' Removes the element at the specified index.
SortedList.RemoveAt 0

' Removes all elements.
SortedList.Clear

' Releases the list.
Set SortedList = Nothing

' Displays the result.
MsgBox Message, vbSystemModal


'*******************************************************************************
'LIFO Last In First Out stack
Dim Message, Stack, Item, s

' Initializes the message.
Message = ""

' Creates a list.
Set Stack = CreateObject("System.Collections.Stack")

' Fills the list.
Stack.Push "Item_1"
Stack.Push "Item_2"
Stack.Push "Item_3"
Stack.Push "Item_4"

' Goes through the list elements.
s = ""
For Each Item In Stack
s = s & Item & " "
Next
Message = Message & "1: " & s & vbCrLf

' Converts the list into an array.
Message = Message & "2: " & Join(Stack.ToArray, ",") & vbCrLf

' Returns the element count.
Message = Message & "3: " & Stack.Count & vbCrLf

' Verifies the existence of the value.
Message = Message & "4: " & Stack.Contains("Item_2") & vbCrLf

' Removes and returns the last element.
Message = Message & "5: " & Stack.Pop & vbCrLf

' Returns the last element (without removing it).
Message = Message & "6: " & Stack.Peek & vbCrLf

' Empties the list.
Stack.Clear

' Releases the list.
Set Stack = Nothing

' Displays the result.
MsgBox Message, vbSystemModal


'*******************************************************************************
'FIFO first in first out queue
Dim Message, Queue, Item, s

' Initializes the message.
Message = ""

' Creates a list.
Set Queue = CreateObject("System.Collections.Queue")

' Fills the list.
Queue.Enqueue "Item_1"
Queue.Enqueue "Item_2"
Queue.Enqueue "Item_3"
Queue.Enqueue "Item_4"


' Goes through the list elements.
s = ""
For Each Item In Queue
s = s & Item & " "
Next
Message = Message & "1: " & s & vbCrLf


' Converts the list into an array.
Message = Message & "2: " & Join(Queue.ToArray, ",") & vbCrLf

' Returns the element count.
Message = Message & "3: " & Queue.Count & vbCrLf

' Verifies the existence of the value.
Message = Message & "4: " & Queue.Contains("Item_2") & vbCrLf

' Removes and returns the first element.
Message = Message & "5: " & Queue.Dequeue & vbCrLf

' Returns the first element (without removing it).
Message = Message & "6: " & Queue.Peek & vbCrLf

' Empties the list.
Queue.Clear

' Releases the list.
Set Queue = Nothing

' Displays the result.
MsgBox Message, vbSystemModal
--
Giovanni Cenati (Bergamo, Italy)
Write to "Reventlov" at katamail com
http://digilander.libero.it/Cenati (Esempi e programmi in VbScript)
--
Mayayana
2015-08-29 14:39:36 UTC
Permalink
It's never seemed to me that .Net is worth the
trouble. First, it's only useful for private code. There's
no guarantee that people with XP will have .Net
installed.

Second, I just don't see what's so great. VBS has
Dictionaries. We have arrays. The only thing I really
miss is the mid *statement*, which VB has, allowing
editing of strings without new allocations. But the
Mid statement is essentially the same as building
strings from arrays, which can be done in VBS.
Comparing .Net StringWriter or StringBuilder to
concatenation is a bit like comparing a mediocre
rake to raking your yard with a fork. You need to
compare it fairly, to the best rake you currently have.

It's *extremely* slow to do:

For i = 1 to 100000
s = s & "newstring"
Next

The reason for that is because each iteration requires
allocation of a new string, and the size of that keeps
growing. By the end each iteration is allocating almost
1 MB (or 2 MB for unicode).

But look at the following tests. Here are my results,
testing StringWriter, StringBuilder and simple VBS array
Join:

Concatenating string of instances
of the word "sample":

Time in seconds for given number of iterations:

100,000 1,000,000

Stringwriter: 1.25 9.89
StringBuilder: 1.0468 10.6406
VBS array: 0.109375 0.5625

The results vary slightly with each run, but those
numbers are typical on my machine.
It's clear from those numbers that a VBS array
far faster. And since the same relative speed holds
up for 100,000 or 1,000,000 iterations, it's clear
that instantiating and releasing the objects is not
a factor in the time required. (However, marshaling
probably is a factor. WScript needs to call into a
separate process for each iteration. As with using
any COM object, that's very inefficient.)
Here's the code, if you want to test it:

Dim s2, T1, T2

T1 = Timer
'TestSW 2
'TestA 2
TestSB 2
T2 = Timer

MsgBox Len(s2) & vbCrLf & CStr(T2 - T1)

Sub TestSW(TestVersion)
Dim SW, s1, i1, i2
Set SW = CreateObject("System.IO.StringWriter")
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If
s1 = "sample"
For i1 = 1 to i2
SW.write_12 s1
Next

s2 = SW.GetStringBuilder().ToString()
Set SW = Nothing
End Sub

Sub TestA(TestVersion)
Dim A1(), s1, i1, i2

If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If
s1 = "sample"
ReDim A1(i2)
For i1 = 0 to i2
A1(i1) = s1
Next
s2 = Join(A1, "")
End Sub

Sub TestSB(TestVersion)
Dim SB, s1, i2, i1
s1 = "sample"
Set SB = CreateObject("System.Text.StringBuilder")
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If

For i1 = 1 to i2
SB.Append_3 s1
Next

s2 = SB.ToString

Set SB = Nothing
End Sub
Mayayana
2015-08-29 14:55:07 UTC
Permalink
Another interesting follow-up to that: I've
found two things that can greatly speed
up complex VBS operations. One is to always
use arrays as string builders for large strings.
The other, not so dramatically efficient but
still worthwhile, is to do case-insensitive search.

Example:
You have 3 MB of text and need to search
for numerous strings, which may or may not
be the same case. I've found that it's notably
faster to copy to string with something like
s2 = LCase(s)
Then s2 can be searched using binary search,
while s is still the string operated on:

Pt1 = Instr(1, s2, "apple", 0)
s3 = Mid(s, Pt1, 5)
s3 then returns apple, Apple, APPLE, etc.

The non-case sensitive version of Instr has to
do a more complex search. The binary version
just needs to look for a matching byte value.
GS
2015-08-30 16:25:24 UTC
Permalink
Post by Mayayana
Another interesting follow-up to that: I've
found two things that can greatly speed
up complex VBS operations. One is to always
use arrays as string builders for large strings.
The other, not so dramatically efficient but
still worthwhile, is to do case-insensitive search.
You have 3 MB of text and need to search
for numerous strings, which may or may not
be the same case. I've found that it's notably
faster to copy to string with something like
s2 = LCase(s)
Then s2 can be searched using binary search,
Pt1 = Instr(1, s2, "apple", 0)
s3 = Mid(s, Pt1, 5)
s3 then returns apple, Apple, APPLE, etc.
The non-case sensitive version of Instr has to
do a more complex search. The binary version
just needs to look for a matching byte value.
How does one implement this in VBS w/o the Mid() function?<g>
--
Garry

Free usenet access at http://www.eternal-september.org
Classic VB Users Regroup!
comp.lang.basic.visual.misc
microsoft.public.vb.general.discussion
Mayayana
2015-08-30 16:55:11 UTC
Permalink
| > Pt1 = Instr(1, s2, "apple", 0)
| > s3 = Mid(s, Pt1, 5)
| > s3 then returns apple, Apple, APPLE, etc.
| >
| > The non-case sensitive version of Instr has to
| > do a more complex search. The binary version
| > just needs to look for a matching byte value.
|
| How does one implement this in VBS w/o the Mid() function?<g>
|

I'm not sure I get that. Are you referring
to my comment about missing the Mid statement
in VBS? As a VBer I expect you probably know
the difference between the Mid statement
and the Mid function. Did I miss something?

For those who don't know, the Mid statement
can be used to build strings in VB:

Replaces characters in s1, starting with offset 101:

Mid(s1, 101) = "sample"

It's very efficient because it doesn't require
memory allocation. It just writes the data
directly into the string variable memory. The
equivalent in VBS is something like:

s2 = Left(s1, 100)
s3 = Right(s1, Len(s1) - 106)
s1 = s2 & "sample" & s3

Three new string allocations. s2, s3 and a
new allocation for s1. Very sloppy and very
slow. Like binary operations, the Mid statment
is a glaring omission in VBS. But using an array
as a string builder comes close to the efficiency
of Mid.
GS
2015-08-30 17:02:52 UTC
Permalink
Post by Mayayana
I'm not sure I get that. Are you referring
to my comment about missing the Mid statement
in VBS? As a VBer I expect you probably know
the difference between the Mid statement
and the Mid function. Did I miss something?
No.., it's I who missed something! I didn't know there was a Mid
statement and a Mid() function because I've never used the former.
Clearly I need to do some homework... (I only know what I use, learning
as I go thru real world projects!)
--
Garry

Free usenet access at http://www.eternal-september.org
Classic VB Users Regroup!
comp.lang.basic.visual.misc
microsoft.public.vb.general.discussion
GS
2015-08-30 17:10:44 UTC
Permalink
Post by GS
Post by Mayayana
I'm not sure I get that. Are you referring
to my comment about missing the Mid statement
in VBS? As a VBer I expect you probably know
the difference between the Mid statement
and the Mid function. Did I miss something?
No.., it's I who missed something! I didn't know there was a Mid
statement and a Mid() function because I've never used the former.
Clearly I need to do some homework... (I only know what I use,
learning as I go thru real world projects!)
Aha! interesting feature! I probably never 'stumbled' onto it due to
typically using the Replace() function. Now I know.., so thanks for
pointing this out!
--
Garry

Free usenet access at http://www.eternal-september.org
Classic VB Users Regroup!
comp.lang.basic.visual.misc
microsoft.public.vb.general.discussion
Mayayana
2015-08-30 17:42:24 UTC
Permalink
| Aha! interesting feature! I probably never 'stumbled' onto it due to
| typically using the Replace() function. Now I know.., so thanks for
| pointing this out!
|

I've actually found that Replace is also extremely
slow. I'm guessing that it does a version of
concatenation, so I try to avoid it in both script
and VB for large strings.

A few years back I was writing color syntax
highlighting code for a code editor and a long,
fruitful discussion happened. Mike Williams insisted
that I should build an RTF string from scratch, while
I was using SendMessage API versions of
RTB.SelStart = x
RTB.SelLength = y
RTB.Selcolor = z

I was sure my way must be fastest. After a lot of
testing I ended up with a far faster method. It turned
out Mike was right. I pointed an integer array at an
LCased version of the string of text in the RTB window
so that I could run a numeric tokenizing routine on
that to add the RTF encoding (like "\cf0 ") for the colors
into a new string using Mid. (So, for instance, the word
Dim might be written to the new string as \cf3 Dim to
make it show a unique color. I don't remember the exact
details of RTF offhand.)

I later tried other tests, like using only integer
arrays with CopyMemory, but never found anything
faster for ocloring text in an RTB.

I'm using a VBS approach to that in the JS
De-Ob I linked in the next thread, building a
new string with HTML coloring code by using
an array with Join. Over time I've ended up
doing a lot of very intensive operations in VBS
and had to try to improve them. It's surprising
what speed differences can be attained with
minor changes.

A bit OT, but do you know this site?

http://www.xbeat.net/vbspeed/

Interesting stuff for improving speeds in VB.
GS
2015-08-30 18:04:43 UTC
Permalink
Post by Mayayana
A bit OT, but do you know this site?
http://www.xbeat.net/vbspeed/
Interesting stuff for improving speeds in VB.
No, I don't know about this site but I'll definitely go for a cruise...

Mike has also been very helpful to me in my learning process! Same goes
for you and many others in the classic VB forums.

Interesting about your syntax coloring! I've been using TextPad with my
CncFiles Pro app as an optional editor to Notepad for about 10 years
now. It supports syntax coloring and so when I started shipping it with
my app I created my own gcode.syn file so it uses standard machine code
editor colors for key characters/words/flags. Actually, it's pretty
much the same as any editor used for writing Basic. Only personal
preference change I made was to color comments light grey so the
machine code stood out better!

TextPad is written in Pascal (I believe), or some derivitive of it. Its
syntax files are structured as text-based data files like this...

<snip>
; CNC G-code Syntax File for TextPad
; Author: Garry Sansom
; Last Updated: 5/9/2007

; Colors are default unless specified

; ~Index~
; Keywords1: Reserved Words (all standard keywords used)
; Keywords2: M-Functions Color: Teal
; Keywords3: T-Functions Color: Olive
; Keywords4: P#### (SubProgram numbers)
; Keywords5: H#-H## (ToolOffset numbers) Color: Maroon
; Keywords6: P#-P###, PB#-PB### (Parameter/Variable
numbers) Color: Maroon

; ~Special Assignments~
; ~(Note that these are unconventional uses)
; PreprocStart: N (PositionLabel) Color: Silver

; CommentStart: F (FeedRate) Color: Teal
; CommentStartAlt: S (SpindleSpeed) Color: Fuchsia
; CommentEnd, CommentEndAlt have been assigned a single space character
so only the assigned character receives color
;
; StringStart: ( (opening parenthesis for comments) Color: Silver
; StringEnd: ) (closing parenthesis for comments)
</snip>

..which appears to be tab-delimited. Fortunately, TextPad includes full
instruction for creating/adding our own document classes with their own
syntax files.<g>
--
Garry

Free usenet access at http://www.eternal-september.org
Classic VB Users Regroup!
comp.lang.basic.visual.misc
microsoft.public.vb.general.discussion
Mayayana
2015-08-30 21:05:12 UTC
Permalink
This post might be inappropriate. Click to display it.
GS
2015-08-30 21:14:36 UTC
Permalink
Post by Mayayana
Post by GS
Interesting about your syntax coloring! I've been using TextPad with
my CncFiles Pro app as an optional editor to Notepad for about 10
years now. It supports syntax coloring and so when I started
shipping it with my app I created my own gcode.syn file so it uses
standard machine code editor colors for key characters/words/flags.
Actually, it's pretty much the same as any editor used for writing
Basic. Only personal preference change I made was to color comments
light grey so the machine code stood out better!
I seem to remember an OSS control for syntax
coloring being available at one point. They all
seem to take the same approach, though. By
coloring keywords/comments/strings they can
adapt fairly easily to numerous different languages.
I wrote my own code because I wanted to color
variables, which are more challenging. I find it very
handy in VBS, especially. As long as I declare the
variable it will be colored and the case matched.
That makes it easy to recognize misspellings. I also
like VB6 for the way it will match case for declared
variables and methods, but VB6 never provided the
option to color variables. It only adjusts the case
of them. It has a color for "identifiers", but that's
meaningless. It includes everything that's not a
string, comment or keyword. So it's really just
"code color".
Sounds very useful! I now use the x64 edition of TextPad and so I
suspect it's very .Net under the hood. I do know, though, there are
lots of non-.Net controls out there for Delphi based apps, both
x86/x64. I was looking very hard at going with Delphi to replace VB6 so
I could make x64 apps, leaving VB[A]/VBS only as my main langs. I
decided to stick with VB6 because I'm too heavily invested in 3rd party
AX controls, and couldn't justify the cost of replacing them for Delphi
use. Ok for doing x86 apps but was looking to move to x64 sooner than
later.
--
Garry

Free usenet access at http://www.eternal-september.org
Classic VB Users Regroup!
comp.lang.basic.visual.misc
microsoft.public.vb.general.discussion
Dave "Crash" Dummy
2015-08-31 01:45:07 UTC
Permalink
Post by Mayayana
| > Pt1 = Instr(1, s2, "apple", 0)
| > s3 = Mid(s, Pt1, 5)
| > s3 then returns apple, Apple, APPLE, etc.
| >
| > The non-case sensitive version of Instr has to
| > do a more complex search. The binary version
| > just needs to look for a matching byte value.
|
| How does one implement this in VBS w/o the Mid() function?<g>
|
I'm not sure I get that. Are you referring
to my comment about missing the Mid statement
in VBS? As a VBer I expect you probably know
the difference between the Mid statement
and the Mid function. Did I miss something?
For those who don't know, the Mid statement
Mid(s1, 101) = "sample"
It's very efficient because it doesn't require
memory allocation. It just writes the data
directly into the string variable memory. The
s2 = Left(s1, 100)
s3 = Right(s1, Len(s1) - 106)
s1 = s2 & "sample" & s3
Three new string allocations. s2, s3 and a
new allocation for s1. Very sloppy and very
slow. Like binary operations, the Mid statment
is a glaring omission in VBS. But using an array
as a string builder comes close to the efficiency
of Mid.
I use the Mid function to emulate the lacking Mid statement:

s1=mid(s1,1,100) & "sample" & mid(s1,101)

As always in VBS, there are several ways to perform a task. Not
recommended, but works:

s1=replace(s1,left(s1,100),left(s1,100) & "sample",1,1)
--
Crash

Registered pedophobe
Mayayana
2015-08-31 03:09:37 UTC
Permalink
| I use the Mid function to emulate the lacking Mid statement:
|
| s1=mid(s1,1,100) & "sample" & mid(s1,101)
|

That doesn't improve efficiency over the Left/Right code.
It's just another way to do the same thing. You're still
allocating 2 new strings, even though you're not declaring
them, and then concatenating those strings in a 3rd new
string. There is no substitute for the Mid statement, which
is an entirely different operation, writing directly to the
string bytes with no new allocations.

Any of the Mid/Left/Right/Replace methods is fine for
small string operations, but for extensive operations it's
worthwhile to try to find a way to do it with Array/Join.
Dave "Crash" Dummy
2015-08-31 11:40:16 UTC
Permalink
Post by Mayayana
|
| s1=mid(s1,1,100) & "sample" & mid(s1,101)
|
That doesn't improve efficiency over the Left/Right code.
It's just another way to do the same thing. You're still
allocating 2 new strings, even though you're not declaring
them, and then concatenating those strings in a 3rd new
string. There is no substitute for the Mid statement, which
is an entirely different operation, writing directly to the
string bytes with no new allocations.
Any of the Mid/Left/Right/Replace methods is fine for
small string operations, but for extensive operations it's
worthwhile to try to find a way to do it with Array/Join.
I don't understand how you turn the initial string of x characters into
an array of x elements.
--
Crash

A line in the sand doesn't mean much if it disappears at high tide.
Mayayana
2015-08-31 13:50:52 UTC
Permalink
| I don't understand how you turn the initial string of x characters into
| an array of x elements.

It depends on what you're doing. If you look at the
JS De-ob coloring routine I linked you can see that
it's building a new string, avoiding concatenation,
which would be unworkable on such a large scale.
I need to rebuild the string almost character by
character, and it needs to work within a reasonable
amount of time on, say, 100 KB of script.

If you want to parse a string and
add lots of substrings then the fastest method is
to parse the string non-case-sensitive and then build
the new one in an array. You can't use an array for
everything, but you can use it for many things where
one might have used the Mid statement.

For a single replacement it doesn't really matter,
but anyplace where you're doing multiple string
allocations, time can get wasted on a very large
scale.

Replace is surprisingly inefficient on large strings,
for the same reasons, so I try to use Replace only
on small strings and use array string-builders for
the big strings.

I originally got this from VB. Matthew Curland, one
of the original VB developers. He explained in his book
that Join walks the array, measuring everything, and
then only needs to allocate one big string.

In the samples below, I take a string full of "a"
and replace 6 characters at a time with "sample",
using Mid, Left/Right, or an array. The array just
assigns "sample" to each array index and then calls
Join. It's not really a real-world test, but it
demonstrates the point. My results in seconds:

string length:
100,000 300,000 1,000,000

Mid .89 51.2

LR .843 50.51 718.812

Array .015 .046 .18

While L/R was fairly quick with a string
100,000 characters long, as you can see,
it gets crazy inefficient as it gets longer.
Almost 12 minutes for a string 1,000,000
characters long! The big drain is when it
needs to allocate big strings in every iteration.

I changed the test to 300,000 from 1,000,000
after the LR test, so I wouldn't be here all morning!
That's why I have no results for a test of Mid on
a string 1,000,000 characters long.
But with the array, the length of the string
hardly matters because there is only one
large string allocation. Here's the code:

Dim s2, T1, T2

T1 = Timer
'TestMid 2
'TestLR 2
TestA1 2
T2 = Timer


MsgBox Len(s2) & vbCrLf & CStr(T2 - T1)
MsgBox s2

Sub TestMid(TestVersion)
Dim s1, i1, i2
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 300000
End If
s1 = "sample"
s2 = String(i2, "a")

i1 = 10
Do While i1 < (i2 - 10)
s2 = mid(s2, 1, i1) & s1 & mid(s2, i1 + 7)
i1 = i1 + 6
Loop

End Sub

Sub TestA1(TestVersion)
Dim A1(), s1, i1, i2
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 300000
End If
s1 = "sample"

ReDim A1(i2 \ 6)
For i1 = 0 to UBound(A1)
A1(i1) = s1
Next

s2 = Join(A1, "")
End Sub

Sub TestLR(TestVersion)
Dim s1, i1, i2
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 300000
End If
s1 = "sample"
s2 = String(i2, "a")

i1 = 10
Do While i1 < (i2 - 10)
s2 = Left(s2, i1) & s1 & Right(s2, Len(s2) - (i1 + 6))
i1 = i1 + 6
Loop

End Sub
j***@gmail.com
2017-03-15 17:24:50 UTC
Permalink
IMHO you are not doing a fair comparison.

When using Redim in VBS, you do not always know ahead of time how many iterations.

So, the correct way to do your test with VBS arrays should be like below because you need to redim the array each time you add to it.

Sub TestAR(TestVersion)
Dim A1(), s1, i1, i2

If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If
s1 = "sample"
'ReDim A1(i2)
For i1 = 0 to i2
Redim Preserve A1(i1)
A1(i1) = s1
Next
s2 = Join(A1, "")
End Sub

If you do the test that way, the array method is FAR slower:


TestSW 1: 600000 0.5625
TestA 1: 600006 0.0234375
TestAR 1: 600006 0.2226563
TestSB 1: 600000 0.4882813
TestSW 2: 6000000 5.265625
TestA 2: 6000006 0.2265625
TestAR 2: 6000006 24.03125<----------------------
TestSB 2: 6000000 4.792969

Jus sayin :)
Post by Mayayana
It's never seemed to me that .Net is worth the
trouble. First, it's only useful for private code. There's
no guarantee that people with XP will have .Net
installed.
Second, I just don't see what's so great. VBS has
Dictionaries. We have arrays. The only thing I really
miss is the mid *statement*, which VB has, allowing
editing of strings without new allocations. But the
Mid statement is essentially the same as building
strings from arrays, which can be done in VBS.
Comparing .Net StringWriter or StringBuilder to
concatenation is a bit like comparing a mediocre
rake to raking your yard with a fork. You need to
compare it fairly, to the best rake you currently have.
For i = 1 to 100000
s = s & "newstring"
Next
The reason for that is because each iteration requires
allocation of a new string, and the size of that keeps
growing. By the end each iteration is allocating almost
1 MB (or 2 MB for unicode).
But look at the following tests. Here are my results,
testing StringWriter, StringBuilder and simple VBS array
Concatenating string of instances
100,000 1,000,000
Stringwriter: 1.25 9.89
StringBuilder: 1.0468 10.6406
VBS array: 0.109375 0.5625
The results vary slightly with each run, but those
numbers are typical on my machine.
It's clear from those numbers that a VBS array
far faster. And since the same relative speed holds
up for 100,000 or 1,000,000 iterations, it's clear
that instantiating and releasing the objects is not
a factor in the time required. (However, marshaling
probably is a factor. WScript needs to call into a
separate process for each iteration. As with using
any COM object, that's very inefficient.)
Dim s2, T1, T2
T1 = Timer
'TestSW 2
'TestA 2
TestSB 2
T2 = Timer
MsgBox Len(s2) & vbCrLf & CStr(T2 - T1)
Sub TestSW(TestVersion)
Dim SW, s1, i1, i2
Set SW = CreateObject("System.IO.StringWriter")
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If
s1 = "sample"
For i1 = 1 to i2
SW.write_12 s1
Next
s2 = SW.GetStringBuilder().ToString()
Set SW = Nothing
End Sub
Sub TestA(TestVersion)
Dim A1(), s1, i1, i2
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If
s1 = "sample"
ReDim A1(i2)
For i1 = 0 to i2
A1(i1) = s1
Next
s2 = Join(A1, "")
End Sub
Sub TestSB(TestVersion)
Dim SB, s1, i2, i1
s1 = "sample"
Set SB = CreateObject("System.Text.StringBuilder")
If TestVersion = 1 Then
i2 = 100000
Else
i2 = 1000000
End If
For i1 = 1 to i2
SB.Append_3 s1
Next
s2 = SB.ToString
Set SB = Nothing
End Sub
Mayayana
2017-03-15 18:40:14 UTC
Permalink
<***@gmail.com> wrote

| When using Redim in VBS, you do not always know ahead of time how many
iterations.
|

That's true. But in usage that's not very relevant.
Your version is not something any experienced scripter
would do. It's not a sensible design. It's just a demo
of the cost of Redim.

In most cases you will know the number of items,
or at least the possible upper limit. In those cases
the typical method is to start with a Redim that's
ample to hold the highest possible number. In cases
where that's not feasible, I estimate, like so:

' we know there are at least 100000 items, but
' we don't know how many total.

UB = 100000
Redim A1(UB)
i = 0
For i = 0 to unknown-number
A1(i) = x
if i = ub then
ub = ub + 100000
Redim Preserve a1(ub)
end if
next

There's then a final Redim Preserve A1(unknown-number)

That's realistic usage. I've done it many times. I
generally have an idea of the range, at least, so I
know whether to redim every 1000 or every 100000.


Testing 6 million writes seems a bit silly to me.
I've never needed to do such a thing. But that
was your test. To give .Net a headstart I even
made a poor prediction of the toital size, requiring
me to do 60 Redim Preserve. In real usage
I probably would have known the total was over
1 million. This is my result:

6 million iterations
string length of 36,000,000

String Builder 61.56 seconds

String Writer 67.34 seconds

VBS array knowing total items 3.375 seconds

VBS array having only a vague
idea of total items 6.156 seconds

So .Net is still pointless bloatware.

Also, you're posting about 5 months late. I'm guessing
you're using Google Groups. I suggest you get a real
newsreader. It works better for newsgroups and you'll
be able to take part in current discussions rather than
posting willy nilly to long-gone threads.

Here's the code for my second version:

Sub TestA(TestVersion)
Dim A1(), s1, i1, i2, UB

If TestVersion = 1 Then
i2 = 100000
Else
i2 = 6000000
End If
s1 = "sample"
UB = 100000
ReDim A1(i2)
For i1 = 0 to i2
A1(i1) = s1
If i1 = UB Then
UB = UB + 100000
ReDim Preserve A1(UB)
End If
Next
ReDim Preserve A1(i2)
s2 = Join(A1, "")
End Sub


--------------------------------------------------------------
| So, the correct way to do your test with VBS arrays should be like below
because you need to redim the array each time you add to it.
|
| Sub TestAR(TestVersion)
| Dim A1(), s1, i1, i2
|
| If TestVersion = 1 Then
| i2 = 100000
| Else
| i2 = 1000000
| End If
| s1 = "sample"
| 'ReDim A1(i2)
| For i1 = 0 to i2
| Redim Preserve A1(i1)
| A1(i1) = s1
| Next
| s2 = Join(A1, "")
| End Sub
|
| If you do the test that way, the array method is FAR slower:
|
|
| TestSW 1: 600000 0.5625
| TestA 1: 600006 0.0234375
| TestAR 1: 600006 0.2226563
| TestSB 1: 600000 0.4882813
| TestSW 2: 6000000 5.265625
| TestA 2: 6000006 0.2265625
| TestAR 2: 6000006 24.03125<----------------------
| TestSB 2: 6000000 4.792969
|
| Jus sayin :)
|
|
|
|
| On Saturday, August 29, 2015 at 9:36:26 AM UTC-5, Mayayana wrote:
| > It's never seemed to me that .Net is worth the
| > trouble. First, it's only useful for private code. There's
| > no guarantee that people with XP will have .Net
| > installed.
| >
| > Second, I just don't see what's so great. VBS has
| > Dictionaries. We have arrays. The only thing I really
| > miss is the mid *statement*, which VB has, allowing
| > editing of strings without new allocations. But the
| > Mid statement is essentially the same as building
| > strings from arrays, which can be done in VBS.
| > Comparing .Net StringWriter or StringBuilder to
| > concatenation is a bit like comparing a mediocre
| > rake to raking your yard with a fork. You need to
| > compare it fairly, to the best rake you currently have.
| >
| > It's *extremely* slow to do:
| >
| > For i = 1 to 100000
| > s = s & "newstring"
| > Next
| >
| > The reason for that is because each iteration requires
| > allocation of a new string, and the size of that keeps
| > growing. By the end each iteration is allocating almost
| > 1 MB (or 2 MB for unicode).
| >
| > But look at the following tests. Here are my results,
| > testing StringWriter, StringBuilder and simple VBS array
| > Join:
| >
| > Concatenating string of instances
| > of the word "sample":
| >
| > Time in seconds for given number of iterations:
| >
| > 100,000 1,000,000
| >
| > Stringwriter: 1.25 9.89
| > StringBuilder: 1.0468 10.6406
| > VBS array: 0.109375 0.5625
| >
| > The results vary slightly with each run, but those
| > numbers are typical on my machine.
| > It's clear from those numbers that a VBS array
| > far faster. And since the same relative speed holds
| > up for 100,000 or 1,000,000 iterations, it's clear
| > that instantiating and releasing the objects is not
| > a factor in the time required. (However, marshaling
| > probably is a factor. WScript needs to call into a
| > separate process for each iteration. As with using
| > any COM object, that's very inefficient.)
| > Here's the code, if you want to test it:
| >
| > Dim s2, T1, T2
| >
| > T1 = Timer
| > 'TestSW 2
| > 'TestA 2
| > TestSB 2
| > T2 = Timer
| >
| > MsgBox Len(s2) & vbCrLf & CStr(T2 - T1)
| >
| > Sub TestSW(TestVersion)
| > Dim SW, s1, i1, i2
| > Set SW = CreateObject("System.IO.StringWriter")
| > If TestVersion = 1 Then
| > i2 = 100000
| > Else
| > i2 = 1000000
| > End If
| > s1 = "sample"
| > For i1 = 1 to i2
| > SW.write_12 s1
| > Next
| >
| > s2 = SW.GetStringBuilder().ToString()
| > Set SW = Nothing
| > End Sub
| >
| > Sub TestA(TestVersion)
| > Dim A1(), s1, i1, i2
| >
| > If TestVersion = 1 Then
| > i2 = 100000
| > Else
| > i2 = 1000000
| > End If
| > s1 = "sample"
| > ReDim A1(i2)
| > For i1 = 0 to i2
| > A1(i1) = s1
| > Next
| > s2 = Join(A1, "")
| > End Sub
| >
| > Sub TestSB(TestVersion)
| > Dim SB, s1, i2, i1
| > s1 = "sample"
| > Set SB = CreateObject("System.Text.StringBuilder")
| > If TestVersion = 1 Then
| > i2 = 100000
| > Else
| > i2 = 1000000
| > End If
| >
| > For i1 = 1 to i2
| > SB.Append_3 s1
| > Next
| >
| > s2 = SB.ToString
| >
| > Set SB = Nothing
| > End Sub
|
Mayayana
2017-03-16 01:38:39 UTC
Permalink
"Mayayana" <***@invalid.nospam> wrote

Woops. I had a typo in my code sample.

UB = 100000
ReDim A1(i2)

should have been

UB = 100000
Redim A1(UB)

So that the array would start out at 100000.
The way I had written it the array started out
full size (6 million) and didn't need to be redimmed.
That was the same as my original code that you
questioned.

Interestingly, I get almost the exact same
result with 60 Redim Preserve as I did with a
single Redim. The time was 6.187 seconds.

I think what this demonstrates is just how
wasteful it is to concatenate repeatedly. But
joining an array is quick. An array is a natural
string builder. With concatenation or the method
you suggested, there will be 6 million
allocations of memory. With Redim A1(6000000)
there's only one allocation. With the gradual
building, 100K at a time, there are 60 allocations,
which is still a very small number.

I expect the .Net methods are probably not too
inefficient, once they get going. But .Net itself
is a pig and none of it is known for speed. Like
Java, that's not the intended strength of .Net.
Rather, sandboxing and ease of coding are the
intention. If .Net provided things that script can't
do, like a window component or maybe graphics
functions, that would be different. Unfortunately,
.Net breaks COM, making it mainly incompatible with
VBS. (What the heck were the Microsofties thinking
with that decision?!) As far as I know, .Net offers
nothing of value to script to offset the disadvantage
and sheer distastefulness of loading a barrel of slop
in order to run a script.

Loading...