Hi all virtual and real participants,
to give TNO's contribution its due and (perhaps) to lure some other people to
this topic, I want to show you the script I currently use to tinker with the
problem.
To explain the structure of my test scripts and the reasons for it, I'd like
to point you to the very simple program I posted for the second challenge.
Comparing this to the more elaborate version may help you to make sense of
my remarks.
As I very/too often said, I start all my scripts with
Option Explicit
to avoid problems due to misspelled variable names; furthermore Dimming
my variables forces me to think about them very carefully. Do I really need
it? Could I avoid a variable by using an expression or a function? In which
scope the variable must be known? Some people like to Dim all their variables
at once and initialize them later/as needed:
Dim oFSO, i, iIterations, x, t1, t2, t3, e1, e2, e3, iNumItems
Set oFSO = CreateObject("Scripting.FileSystemObject")
...
iIterations = 3
I prefer to keep Dimming (=Declaring) and intializing close together, because
this may serve as a kind of documentation for the variable(s):
Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")
...
Dim iIterations : iIterations = 3
As close as possible to its first use I associate the variable name with its
data type and its (first/start) value, hoping to make it easy for my feeble
memory. Do you want to comment on
Dim i, j
, TNO?
While I'm aware of the problems caused by global variables, I will use
them, if I think it advantageous. To make them stand out, I use a "g"
prefix in their names:
Dim goTNOArray2 ' needed for TNOJoin()
For two reasons, I restrict my main/top level code to the Dimming of global
variables and the returning of an error/success code to the operating system:
WScript.Quit doMain()
The first reason: That way I can easily run different portions of code - tackling
various sub problems or trying out different soultions - from the same .vbs file
by writing more than one 'main' function and using reordering or commenting to
switch between them:
WScript.Quit doThis() | WScript.Quit doThat() | ' WScript.Quit doThis()
WScript.Quit doThat() | WScript.Quit doThis() | WScript.Quit doThat()
The second reason: That way I can't introduce global variables 'by accident'.
If I had Dimmed sSep at the top level, then using it in the toDispString( vX )
function would be very tempting
Case 8204 ' Array of Variants
sRVal = "[" + OURJoin( vX, "," ) + "]"
==>
sRVal = "[" + OURJoin( vX, sSep ) + "]"
As it is, I can't use this easy way out, but have to acknowledge the pending
problem: Is it ok to hard code the inner separator or must I feed it to the
function via parameter? Do I really want to implement a toDispString( vX, sSep )
or even a toDispString( vX, aSeps ) function to handle (deeply) nested arrays?
So a typical main function looks like this:
Function doMain()
Dim nRval : nRVal = 0
...
WScript.Echo "##### VBScript Forum Challenge 001: JoinX"
...
doMain = nRVal
End Function
The return/error code feature isn't used in most of my test scripts, but it
proved valuable for 'real world' scripts that are scheduled or used from other
programs.
Testing/trying out means testing/trying more than one thing. So most test
scripts use a simple
' the strings we want to test
Dim aTStrs : aTStrs = Array( _
"" _
, "a b c" _
)
or a more complicated/structured array of data
' the arrays we want to test (each one named for easy reference)
Dim aTArrs : aTArrs = Array( _
"empty" , Array() _
, "one string" , Array( "a" ) _
...
, "objects" , Array( New RegExp, CreateObject( "ADODB.Connection" ), oObj, Err ) _
)
to be fed to the code/functions. This setup and the effort put into the formatting
makes it easy to add interesting/critical test cases. Of course the structure of
the data is reflected in the code to loop over them. For simple arrays simple loops:
' loop over all strings to test
For Each sTest In aTStrs
...
Next
for implicitly structured arrays, the Step feature of the For loop comes handy:
' loop over all arrays to test
For nTArr = 0 To UBound( aTArrs ) Step 2
...
WScript.Echo "=====", nTArr / 2, "Array:", aTArrs( nTArr ) ' <-- the name
...
sRes = fncJ( aTArrs( nTArr + 1 ), sSep ) ' <-- the array to feed to the function
...
Next
Explicitly structured arrays
' the different versions of JoinX( aX, sSep )
Dim aFuncs : aFuncs = Array( _
Array( "VBS Join", GetRef( "VBSJoin" ), "|" ) _
, Array( "TNO Join", GetRef( "TNOJoin" ), "|" ) _
, Array( "Our Join", GetRef( "OurJoin" ), "|" ) _
)
can be looped over by For (+ index):
' loop over all functions to use
For nFunc = 0 To UBound( aFuncs )
WScript.Echo "-----", nFunc, "Function:", aFuncs( nFunc )( 0 )
Set fncJ = aFuncs( nFunc )( 1 ) ' the function used
sSep = aFuncs( nFunc )( 2 ) ' the separator used for display
sRes = fncJ( aTArrs( nTArr + 1 ), sSep ) ' call the function
WScript.Echo ">|" + sRes + "|<"
Next
or by For Each:
Dim aFunc
For Each aFunc In aFuncs
WScript.Echo "----- Function:", aFunc( 0 )
Set fncJ = aFunc( 1 ) ' the function used
sSep = aFunc( 2 ) ' the separator used for display
sRes = fncJ( aTArrs( nTArr + 1 ), sSep ) ' call the function
WScript.Echo ">|" + sRes + "|<"
Next
If you don't need a numeric index variable, For Each is more convenient; but
changing elements needs For, because the For Each variable is a copy. Run
Function ForForEach()
Dim aTest : aTest = Array( "zero", "one", "two" )
Dim nIdx : nIdx = 0
Dim sTest
For Each sTest In aTest
sTest = CStr( nIdx )
nIdx = nIdx + 1
Next
WScript.Echo "For Each", Join( aTest )
For nIdx = 0 To UBound( aTest )
aTest( nIdx ) = CStr( nIdx )
Next
WScript.Echo "For ", Join( aTest )
ForForEach = 0
End Function
to see the difference.
For Each zero one two
For 0 1 2
The script demonstrates 3 Join functions: The VBScript Join() that fails
even for simple cases:
===== 2 Array: the empties
----- Function: VBS Join
>|Typen unverträglich|< i.e. Type mismatched caused by Null
----- Function: TNO Join
>|[vbEmpty]|[vbNull]|[vbObject]|<
----- Function: Our Join
>|<Empty>|<Null>|<Nothing>|<
I don't want to spend further words on this miserable thing. The second
functions is (my revision of) TNO's Join() function, that really is an
significant improvement. The nits I feel the need to pick don't lower
its value - that goes without saying.
No surprise, that I don't like the use of the global variable (though - as
I said before - I use them myself if they are proved necessary). How could
goTNOArray2 be avoided? By passing the second array as an parameter:
(1) add an element to aFuncs
Dim aFuncs : aFuncs = Array( _
Array( "VBS Join", GetRef( "VBSJoin" ) , "|" ) _
, Array( "TNO Join", GetRef( "TNOJoin" ) , "|" ) _
, Array( "TNO NOGV", GetRef( "TNOJoinNOGV" ), "|" ) _
, Array( "Our Join", GetRef( "OurJoin" ) , "|" ) _
(2) add a nonrecursive 'entry' function:
''# TNOJoinNOGV - calls TNO's Join (no global variable)
' ############################################################################
Function TNOJoinNOGV( ByRef Array1, Sep )
TNOJoinNOGV = TNOJoinNOGV_( Array1, Array(), Sep )
End Function
(3) that passes the second array to the recursive work function:
Function TNOJoinNOGV_( Array1, Array2, Sep )
Dim JS : Set JS = CreateObject( "JS.Array" )
Dim i, j
For Each i In Array1
If IsArray(i) Then
TNOJoinNOGV_ i, Array2, Sep
Else
Select Case VarType(i)
Case 0 JS.Push Array2, "[vbEmpty]"
Case 1 JS.Push Array2, "[vbNull]"
...
Case 13 JS.Push Array2, "[vbDataObject]"
Case 17 JS.Push Array2, CStr(i)
End Select
End If
Next
TNOJoinNOGV_ = Join( Array2, Sep )
End Function
Compare this to OURJoin
''# OURJoin - crossbred of contributions
' ############################################################################
Function OURJoin( aX, sSep )
ReDim aClone( UBound( aX ) )
Dim nIdx : nIdx = 0
Dim vElm
For Each vElm In aX
aClone( nIdx ) = toDispString( vElm )
nIdx = nIdx + 1
Next
OURJoin = Join( aClone, sSep )
End Function
that uses a second array too - but one that is dimensioned suitably right from
the start (no need for growing/push) and keeps it local (no parameter passing
to the recursive work function toDispString()).
My verdict on the reliance on the JS.Array component is the same as what I said
about ginolard's use of the .NET System.Collections.ArrayList. Non native VBScript
means are ok if unavoidable, but I'd prefer a 'pure' solution. In TNO's case
the foreign component is used only to make the dynamic growing of the second array
more efficient. But that isn't necessary: We know the UBound of the second array
beforehand - we nead exactly as many elements as the first one contains:
''# TNOJoinNOJS - calls TNO's Join (no JS.Array)
' ############################################################################
Function TNOJoinNOJS( ByRef Array1, Sep )
ReDim Array2( UBound( Array1 ) )
TNOJoinNOJS = TNOJoinNOJS_( Array1, Array2, Sep )
End Function
Function TNOJoinNOJS_( Array1, Array2, Sep )
Dim JS : Set JS = CreateObject( "JS.Array" )
Dim nIdx : nIdx = 0
Dim vElm
For Each vElm In Array1
If IsArray( vElm ) Then
Array2( nIdx ) = TNOJoinNOJS( vElm, Sep )
Else
Select Case VarType( vElm )
Case 0 Array2( nIdx ) = "[vbEmpty]"
Case 1 Array2( nIdx ) = "[vbNull]"
Case 2 Array2( nIdx ) = CStr( vElm )
Case 3 Array2( nIdx ) = CStr( vElm )
Case 4 Array2( nIdx ) = CStr( vElm )
Case 5 Array2( nIdx ) = CStr( vElm )
Case 6 Array2( nIdx ) = CStr( vElm )
Case 7 Array2( nIdx ) = CStr( vElm )
Case 8 Array2( nIdx ) = vElm
Case 9 Array2( nIdx ) = "[vbObject]"
Case 10 Array2( nIdx ) = "["&CStr( vElm )&"]"
Case 11 Array2( nIdx ) = CStr( vElm )
Case 12 Array2( nIdx ) = "[vbVariant]"
Case 13 Array2( nIdx ) = "[vbDataObject]"
Case 17 Array2( nIdx ) = CStr( vElm )
End Select
End If
nIdx = nIdx + 1
Next
TNOJoinNOJS_ = Join( Array2, Sep )
End Function
I'm not happy with the use of magic numbers instead of the predefined VBScript
constants:
Case vbEmpty ' 0 Uninitialized (default)
sRVal = "<Empty>"
may be more characters to enter than
Case 0 Array2( nIdx ) = "[vbEmpty]"
but you write a script once (or - if you are like me - about 12 times),
but you resp. your clients read it 4711 times. Think of all the time wasted
to remember/check that VarType 0 means Empty (and not Null).
As most of the solutions presented here, TNO's function flattens arrays of
arrays:
"nested arrs" , Array( Array( 1, 2, 3 ), Array( "one", "two", "three" ) ) _
===== 3 Array: nested arrs
----- Function: VBS Join
>|Typen unverträglich|<
----- Function: TNO Join
>|1|2|3|one|two|three|<
----- Function: TNO NOGV
>|1|2|3|one|two|three|<
----- Function: TNO NOJS
>|1|2|3|one|two|three|<
----- Function: Our Join
>|[1,2,3]|["one","two","three"]|<
So perhaps this should be considered a feature.
All my usual carping must not hide the fact that the third function -
OURJoin() - wouldn't exist without all your contributions to this topic.
It's much easier to program on the base of concrete working code than
doing it from scratch. All fame and glory is due to the participants;
extra thanks to TNO for his code (and the JS.Array which downloaded,
installed and worked flawlessly for me). I just crossbred all the
suggestions with some of my own thoughts. For example my very first
version of the JoinX() function used string concatenation, DiGiTAL.SkReAM's
dictionary approach and dm_4ever's use of Split and ReDim made me realize
the (irony of the) possibility to let VBScript's Join() do the concatenation.
Likewise there would be no dictionary joining without ebgreen. And I'm still
waiting for ginolard to come up with some String.Join( ArrayList, "," ) magic
to make OURJoined effort obsolete.
I think that splitting the joining into a 'put together' loop (see above)
and a 'handle each element according to its data type' part (see below)
makes the code easy to understand. mcds99, don't cry! You would make me
happy/smile, if you could post some questions as to the what, how, and why
of the code that forces me to make the code better (to comprehend). There
are some points worth discussing in the monster Select Case. Should the
(german) "," really replaced with "." in real numbers? Would it be
necessary to check the locale? Should dates be delimited? Should strings be
not delimited? How to discriminate between a plain date and the datetime
midnight?
Ok, it's after midnight in Germany - here is all the code:
''# xjoinx.vbs : VBScript Forum Challenge 001: A better Join()
''# usage: cscript xjoinx.vbs
' ############################################################################
Option Explicit
''# global vars
' ############################################################################
Dim goTNOArray2 ' needed for TNOJoin()
''# main -
' ############################################################################
WScript.Quit doMain()
Function doMain()
Dim nRval : nRVal = 0
WScript.Echo "##### VBScript Forum Challenge 001: JoinX"
Dim oObj : Set oObj = CreateObject( "Scripting.FileSystemObject" )
' the arrays we want to test (each one named for easy reference)
Dim aTArrs : aTArrs = Array( _
"empty" , Array() _
, "one string" , Array( "a" ) _
, "the empties" , Array( Empty, Null, Nothing ) _
, "nested arrs" , Array( Array( 1, 2, 3 ), Array( "one", "two", "three" ) ) _
, "booleans" , Array( True, False ) _
, "numbers" , Array( 0, 0.0, -1, 4711, 123.456 ) _
, "date/time" , Array( Now, CDate( "20.07.2007 00:00:00" ), Date ) _
, "dictionary" , Array( getSomeDictionary(), getSomeDictionary().Keys ) _
, "objects" , Array( New RegExp, CreateObject( "ADODB.Connection" ), oObj, Err ) _
)
' the different versions of JoinX( aX, sSep )
Dim aFuncs : aFuncs = Array( _
Array( "VBS Join", GetRef( "VBSJoin" ) , "|" ) _
, Array( "TNO Join", GetRef( "TNOJoin" ) , "|" ) _
, Array( "TNO NOGV", GetRef( "TNOJoinNOGV" ), "|" ) _
, Array( "TNO NOJS", GetRef( "TNOJoinNOJS" ), "|" ) _
, Array( "Our Join", GetRef( "OurJoin" ) , "|" ) _
)
Dim nTArr, fncJ, sSep, nFunc, sRes
' loop over all arrays to test
For nTArr = 0 To UBound( aTArrs ) Step 2
WScript.Echo
WScript.Echo "=====", nTArr / 2, "Array:", aTArrs( nTArr )
' loop over all functions to use
If False Then
For nFunc = 0 To UBound( aFuncs )
WScript.Echo "-----", nFunc, "Function:", aFuncs( nFunc )( 0 )
Set fncJ = aFuncs( nFunc )( 1 ) ' the function used
sSep = aFuncs( nFunc )( 2 ) ' the separator used for display
sRes = fncJ( aTArrs( nTArr + 1 ), sSep ) ' call the function
WScript.Echo ">|" + sRes + "|<"
Next
Else
Dim aFunc
For Each aFunc In aFuncs
WScript.Echo "----- Function:", aFunc( 0 )
Set fncJ = aFunc( 1 ) ' the function used
sSep = aFunc( 2 ) ' the separator used for display
sRes = fncJ( aTArrs( nTArr + 1 ), sSep ) ' call the function
WScript.Echo ">|" + sRes + "|<"
Next
End If
Next
WScript.Echo
WScript.Echo "##### Done."
doMain = nRVal
End Function
''# getSomeDictionary - convenience function to get a dictionary
' ############################################################################
Function getSomeDictionary()
Dim dicRVal : Set dicRVal = CreateObject( "Scripting.Dictionary" )
dicRVal( "one" ) = 1
dicRVal( "two" ) = Array( "zwei", "dos" )
Set getSomeDictionary = dicRVal
End Function
''# VBSJoin - calls VBScript's Join (needed for GetRef())
' ############################################################################
Function VBSJoin( aX, sSep )
Dim sRVal
On Error Resume Next
sRVal = Join( aX, sSep )
If 0 <> Err.Number Then sRVal = Err.Description
On Error GoTo 0
VBSJoin = sRVal
End Function
''# TNOJoin - calls TNO's Join (needed because of global variable)
' ############################################################################
Function TNOJoin( ByRef Array1, Sep )
goTNOArray2 = Array() ' needed for TNOJoin
TNOJoin = TNOJoin_( Array1, Sep )
End Function
Function TNOJoin_( ByRef Array1, Sep )
Dim JS : Set JS = CreateObject( "JS.Array" )
Dim i, j
For Each i In Array1
If IsArray(i) Then
TNOJoin_ i, Sep
Else
Select Case VarType(i)
Case 0 JS.Push goTNOArray2, "[vbEmpty]"
Case 1 JS.Push goTNOArray2, "[vbNull]"
Case 2 JS.Push goTNOArray2, CStr(i)
Case 3 JS.Push goTNOArray2, CStr(i)
Case 4 JS.Push goTNOArray2, CStr(i)
Case 5 JS.Push goTNOArray2, CStr(i)
Case 6 JS.Push goTNOArray2, CStr(i)
Case 7 JS.Push goTNOArray2, CStr(i)
Case 8 JS.Push goTNOArray2, i
Case 9 JS.Push goTNOArray2, "[vbObject]"
Case 10 JS.Push goTNOArray2, "["&CStr(i)&"]"
Case 11 JS.Push goTNOArray2, CStr(i)
Case 12 JS.Push goTNOArray2, "[vbVariant]"
Case 13 JS.Push goTNOArray2, "[vbDataObject]"
Case 17 JS.Push goTNOArray2, CStr(i)
End Select
End If
Next
TNOJoin_ = Join( goTNOArray2, Sep )
End Function
''# OURJoin - crossbred of contributions
' ############################################################################
Function OURJoin( aX, sSep )
ReDim aClone( UBound( aX ) )
Dim nIdx : nIdx = 0
Dim vElm
For Each vElm In aX
aClone( nIdx ) = toDispString( vElm )
nIdx = nIdx + 1
Next
OURJoin = Join( aClone, sSep )
End Function
''# toDispString - what CStr() should do
' ############################################################################
Function toDispString( vX )
Dim sRVal : sRVal = "*** toDispString() failed miserably ***"
Select Case VarType( vX )
Case vbEmpty ' 0 Uninitialized (default)
sRVal = "<Empty>"
Case vbNull ' 1 Contains no valid data
sRVal = "<Null>"
Case vbInteger ' 2 Integer subtype
sRVal = CStr( vX )
Case vbLong ' 3 Long subtype
sRVal = CStr( vX )
Case vbSingle ' 4 Single subtype
sRVal = CStr( vX )
sRVal = Replace( sRVal, ",", "." ) ' germanism
Case vbDouble ' 5 Double subtype
sRVal = CStr( vX )
sRVal = Replace( sRVal, ",", "." ) ' germanism
Case vbCurrency ' 6 Currency subtype
sRVal = CStr( vX )
sRVal = Replace( sRVal, ",", "." ) ' germanism
Case vbDate ' 7 Date subtype
sRVal = CStr( vX )
Case vbString ' 8 String subtype
sRVal = """" + vX + """"
Case vbObject ' 9 Object
If vX Is Nothing Then
sRVal = "<Nothing>"
Else
sRVal = TypeName( vX )
Select Case sRVal
Case "Dictionary"
Dim vKey
sRVal = ""
For Each vKey In vX.Keys
sRVal = sRVal + "," + toDispString( vKey ) + "=>" + toDispString( vX( vKey ) )
Next
sRVal = "{" + Mid( sRVal, 2 ) + "}"
Case Else
sRVal = sRVal + "-Obj"
End Select
End If
Case vbError ' 10 Error subtype
Case vbBoolean ' 11 Boolean subtype
sRVal = CStr( vX )
Case vbVariant ' 12 Variant (used only for arrays of variants)
Case vbDataObject ' 13 Data access object
Case vbDecimal ' 14 Decimal subtype
Case vbByte ' 17 Byte subtype
Case vbArray ' 8192 Array
Case 8204 ' Array of Variants
sRVal = "[" + OURJoin( vX, "," ) + "]"
End Select
toDispString = sRVal
End Function
''# TNOJoinNOGV - calls TNO's Join (no global variable)
' ############################################################################
Function TNOJoinNOGV( ByRef Array1, Sep )
TNOJoinNOGV = TNOJoinNOGV_( Array1, Array(), Sep )
End Function
Function TNOJoinNOGV_( Array1, Array2, Sep )
Dim JS : Set JS = CreateObject( "JS.Array" )
Dim i, j
For Each i In Array1
If IsArray(i) Then
TNOJoinNOGV_ i, Array2, Sep
Else
Select Case VarType(i)
Case 0 JS.Push Array2, "[vbEmpty]"
Case 1 JS.Push Array2, "[vbNull]"
Case 2 JS.Push Array2, CStr(i)
Case 3 JS.Push Array2, CStr(i)
Case 4 JS.Push Array2, CStr(i)
Case 5 JS.Push Array2, CStr(i)
Case 6 JS.Push Array2, CStr(i)
Case 7 JS.Push Array2, CStr(i)
Case 8 JS.Push Array2, i
Case 9 JS.Push Array2, "[vbObject]"
Case 10 JS.Push Array2, "["&CStr(i)&"]"
Case 11 JS.Push Array2, CStr(i)
Case 12 JS.Push Array2, "[vbVariant]"
Case 13 JS.Push Array2, "[vbDataObject]"
Case 17 JS.Push Array2, CStr(i)
End Select
End If
Next
TNOJoinNOGV_ = Join( Array2, Sep )
End Function
''# TNOJoinNOJS - calls TNO's Join (no JS.Array)
' ############################################################################
Function TNOJoinNOJS( ByRef Array1, Sep )
ReDim Array2( UBound( Array1 ) )
TNOJoinNOJS = TNOJoinNOJS_( Array1, Array2, Sep )
End Function
Function TNOJoinNOJS_( Array1, Array2, Sep )
Dim JS : Set JS = CreateObject( "JS.Array" )
Dim nIdx : nIdx = 0
Dim vElm
For Each vElm In Array1
If IsArray( vElm ) Then
Array2( nIdx ) = TNOJoinNOJS( vElm, Sep )
Else
Select Case VarType( vElm )
Case 0 Array2( nIdx ) = "[vbEmpty]"
Case 1 Array2( nIdx ) = "[vbNull]"
Case 2 Array2( nIdx ) = CStr( vElm )
Case 3 Array2( nIdx ) = CStr( vElm )
Case 4 Array2( nIdx ) = CStr( vElm )
Case 5 Array2( nIdx ) = CStr( vElm )
Case 6 Array2( nIdx ) = CStr( vElm )
Case 7 Array2( nIdx ) = CStr( vElm )
Case 8 Array2( nIdx ) = vElm
Case 9 Array2( nIdx ) = "[vbObject]"
Case 10 Array2( nIdx ) = "["&CStr( vElm )&"]"
Case 11 Array2( nIdx ) = CStr( vElm )
Case 12 Array2( nIdx ) = "[vbVariant]"
Case 13 Array2( nIdx ) = "[vbDataObject]"
Case 17 Array2( nIdx ) = CStr( vElm )
End Select
End If
nIdx = nIdx + 1
Next
TNOJoinNOJS_ = Join( Array2, Sep )
End Function
And the output
cscript xjoinx.vbs
##### VBScript Forum Challenge 001: JoinX
===== 0 Array: empty
----- Function: VBS Join
>||<
----- Function: TNO Join
>||<
----- Function: TNO NOGV
>||<
----- Function: TNO NOJS
>||<
----- Function: Our Join
>||<
===== 1 Array: one string
----- Function: VBS Join
>|a|<
----- Function: TNO Join
>|a|<
----- Function: TNO NOGV
>|a|<
----- Function: TNO NOJS
>|a|<
----- Function: Our Join
>|"a"|<
===== 2 Array: the empties
----- Function: VBS Join
>|Typen unverträglich|<
----- Function: TNO Join
>|[vbEmpty]|[vbNull]|[vbObject]|<
----- Function: TNO NOGV
>|[vbEmpty]|[vbNull]|[vbObject]|<
----- Function: TNO NOJS
>|[vbEmpty]|[vbNull]|[vbObject]|<
----- Function: Our Join
>|<Empty>|<Null>|<Nothing>|<
===== 3 Array: nested arrs
----- Function: VBS Join
>|Typen unverträglich|<
----- Function: TNO Join
>|1|2|3|one|two|three|<
----- Function: TNO NOGV
>|1|2|3|one|two|three|<
----- Function: TNO NOJS
>|1|2|3|one|two|three|<
----- Function: Our Join
>|[1,2,3]|["one","two","three"]|<
===== 4 Array: booleans
----- Function: VBS Join
>|Wahr|Falsch|<
----- Function: TNO Join
>|Wahr|Falsch|<
----- Function: TNO NOGV
>|Wahr|Falsch|<
----- Function: TNO NOJS
>|Wahr|Falsch|<
----- Function: Our Join
>|Wahr|Falsch|<
===== 5 Array: numbers
----- Function: VBS Join
>|0|0|-1|4711|123,456|<
----- Function: TNO Join
>|0|0|-1|4711|123,456|<
----- Function: TNO NOGV
>|0|0|-1|4711|123,456|<
----- Function: TNO NOJS
>|0|0|-1|4711|123,456|<
----- Function: Our Join
>|0|0|-1|4711|123.456|<
===== 6 Array: date/time
----- Function: VBS Join
>|20.07.2007 01:59:19|20.07.2007|20.07.2007|<
----- Function: TNO Join
>|20.07.2007 01:59:19|20.07.2007|20.07.2007|<
----- Function: TNO NOGV
>|20.07.2007 01:59:19|20.07.2007|20.07.2007|<
----- Function: TNO NOJS
>|20.07.2007 01:59:19|20.07.2007|20.07.2007|<
----- Function: Our Join
>|20.07.2007 01:59:19|20.07.2007|20.07.2007|<
===== 7 Array: dictionary
----- Function: VBS Join
>|Falsche Anzahl an Argumenten oder ungültige Eigenschaftszuweisung|<
----- Function: TNO Join
>|[vbObject]|one|two|<
----- Function: TNO NOGV
>|[vbObject]|one|two|<
----- Function: TNO NOJS
>|[vbObject]|one|two|<
----- Function: Our Join
>|{"one"=>1,"two"=>["zwei","dos"]}|["one","two"]|<
===== 8 Array: objects
----- Function: VBS Join
>|Das Objekt unterstützt diese Eigenschaft oder Methode nicht.|<
----- Function: TNO Join
>|[vbObject]||[vbObject]|0|<
----- Function: TNO NOGV
>|[vbObject]||[vbObject]|0|<
----- Function: TNO NOJS
>|[vbObject]||[vbObject]|0|<
----- Function: Our Join
>|RegExp-Obj|""|FileSystemObject-Obj|0|<
##### Done.
What still needs to be done:
(1) All Join functions strive to display the elements of the array; I would
like to have a second version (JoinY (?)) that returns a string that
could be fed to Eval() - as a kind of (simple) persistency feature.
[I was not amused when ebgreen hijacked the persistency problem in
http://www.visualbasicscript.com/fb.aspx?m=49431 and even mentioned XML - I had to revise my second challenge (see
below)]
(2) Some objects - with default properties - are difficult/impossible
to display:
"objects" , Array( New RegExp, CreateObject( "ADODB.Connection" ), oObj, Err )
===== 7 Array: objects
----- 0 Function: VBS Join
>|Das Objekt unterstützt diese Eigenschaft oder Methode nicht.|<
----- 1 Function: TNO Join
>|[vbObject]||[vbObject]|0|<
----- 2 Function: Our Join
>|RegExp-Obj|""|FileSystemObject-Obj|0|<
Just now I can't even think of a way to identify these nasty cases.
(3) How about arrays of more than one dimension?
But perhaps you feel bored by this challenge or think the problem isn't worth
further discussion. In that case look at my next posting!
Thanks again for all the input - and my apologies for the number of lines!
ehvbs