> In a VBScript (.vbs) or an HTA file, using VBScript, can someone
> please post generic example code that tests to see if an array is
> empty?
if you mean empty = no members?
> Thanks much in advance for your assistance.
if ubound(myArray) = 0 then
--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)
if ubound(a) = 0 then s = a(0)
a(0) could be something.
This topic comes up every once in a while
and I can never remember all the details. But
I find that if I declare:
Dim a()
IsEmpty ans IsNull both return False, even though
there actually are no members in that array!
This test seems to work:
On Error Resume Next
i = UBound(a)
MsgBox Err.number & vbCrLf & Err.Description
If Ubound is 0 there's no error, but for a()
it causes error 8, subscript out of range.
Personally I find all of these non-intuitive
array aspects confusing and often just use
an array where I start my data at a(1) and
may use a(0) to store something like the number
of members, or else just leave it unused.
Arrays indices are 0-based so an array with UBound of 0 has 1 element...
Dim myArray
myArray = Array()
wscript.echo ubound(myArray)
An empty array will have a UBound of -1 meaning 0 elements
myArray = Array("hello")
wscript.echo ubound(myArray)
--
Michael Harris
The trickiest situation I have stumbled over is where an object is
supposed to return an array, but the returned set is actually empty,
as can occur with a WMI query. In such cases, trying to use the
Ubound function as a test raises an error. Rather, the first test
needs to be whether the result is empty - or even an array (I believe
I have seen a one item set returned from some objects as a scaler -
though I can't cite an example off the top of my head). So I tend to
use IsArray or vartype(arrVar) = vbArray for the test.
Tom Lavedas
===========
http://members.cox.net/tglbatch/wsh/
That's a curious quirk, but I wonder how much value
it has. Dim a() causes an error with UBound and I
can't think of any situation where one would find
it useful to do:
Dim a
a = Array()
But I supppose it could all be put into a test function:
Function IsUsableArray(a)
Dim i
Err.Clear
On Error Resume Next
i = UBound(a)
if (Err.Number = 0) and (i > -1) then IsUsableArray = True
End Function
'how much value'?
When you write a function that returns an array of things, I would
assume that you would still return an array even if there were only
one thing in that array. If there are no things to return, wouldn't
it be more logical for the function to return Array(0), rather than
some other type of variant?
-Paul Randall
> 'how much value'?
> When you write a function that returns an array of things, I would
> assume that you would still return an array even if there were only
> one thing in that array. If there are no things to return, wouldn't
> it be more logical for the function to return Array(0), rather than
> some other type of variant?
>
Yes, I would certainly think so. I usually return
an array where array(0) is the number of things
returned. Then I don't have to worry about errors
handling the array. But the question seemed to be
about how to handle an array variable, presumably
not under one's own control, that might actually
have no items.
When I said "not much value" I meant that it's
not much help to test a known array, that might
have no items, for ubound -1 because that only works
if the array was created with:
Dim a
a = Array()
and not with:
Dim a()
So that's why I suggested a function to provide
what MS somehow left out, despite all the "Is----"
functions they provided. That is, a function to test
"Is this a usable array?"
Once we have solved this little problem, who wants to tackle this one: how
to determine if the array is half-empty or half-full?
/Al
Sorry, buddy, you're in the wrong group. You
want:
microsoft.public.scripting.philosophicalissues
Or if you have trouble with your arrays always
being half empty, and you want to bypass the
philosophical approach, going straight to
psycho-pharmaceuticals, you could try:
scripting.treatment.neurotransmitter-reuptake-inhibitors
Arrays do cause quite a bit of confusion as this thread indicates. So I'll
de-mystify them by describing some of the under the hood workings. (Sorry
turned out to be more longwinded than I anticitpated).
VBScript is often described as having typeless variables or only having one
type of variable of the Variant type. A variant can hold any type and can
at any time be re-assigned with a type completely different from the one it
is currently holding.
However VBScript variables actually have two types, Variant and Array of
Variants.
Dim a ' A variant
Dim a() ' An array of variants
The structure of a Variant variable is 16 bytes in size containing in part a
VT field which defines the current type it is holding and the value itself
(if its a fixed size value that fits in 8 bytes, Long or Currency for
example) or a pointer to the value (an object, string or an array).
The structure of an array of variants variable is a pointer to a SAFEARRAY
structure. The SAFEARRAY defines the variant type of its elements, how many
bytes each element is, how many dimensions there are and a pointer to the
beginning of the array data itself. In VBScript the type is always
VT_VARIANT (12) and the element size is therefore always 16 bytes.
The SAFEARRAY structure is extensible in that immediately following it there
are a series (an 'array' you might say) of small structures, one per
dimension. These define the LBound value for the dimension and how many
elements are in the dimension (cElems).
This leads us to why we get "Subscript out of range" when using UBound on
undimensioned arrays.
UBound(a) is in fact short hand for UBound(a, 1) which says get me the
upper bound of the first dimension in the array. The 1 is an index (or
subscript) into that little array of dimension structures that follow the
SAFEARRAY. An undimensioned array has a dimension count of 0 and none of
these structures. Therefore fetching the first element from this 'array' of
dimension structures is 'out of range' for an undimensioned array.
Now take a look at this:-
Dim a
a = Split("", ",")
MsgBox UBound(a)
The array is empty and we get -1 from the UBound what is going on here?
Split is returning a dimensioned array. It has only 1 dimension but that
dimension has an element count of 0 since the input string was empty.
Remember the structure that defines the dimension carries only the LBound
and the element count. The UBound function therefore use this formula to
calculate the UBound :-
lBound + cElems - 1
When both lBound and cElems are 0 then UBound is -1.
This behaviour is actually quite handy, take a look at this:-
Sub ListWords(sLine)
Dim a : a = Split(sLine, " ")
Dim i
For i = 0 To UBound(a)
WScript.Echo a(i)
Next
End Sub
ListWords "Hello World"
ListWords ""
Had Split returned null, empty or an undimensioned array I would have to
take steps in the ListWords procedure to handle that correctly. However as
it is it works fine since For i = 0 to -1 will do nothing.
As Tom pointed out some interfaces can hold properties which if they have a
value will be an array but may also be null. This is another scenario that
may need to be considered when testing for an empty array.
I propose this function for general testing of an array:-
Function TestArray(rvnt)
On Error Resume Next
TestArray = 0
If (VarType(rvnt) And 8192) = 8192 Then
TestArray = UBound(rvnt) - LBound(rvnt) + 1
ElseIf Not (IsEmpty(rvnt) or IsNull(rvnt)) Then
TestArray = -1
End If
End Function
It assumes that a null or empty could potentially be an array but not yet
dimensioned. It returns -1 for if passed a string, long etc, 0 for an empty
array or the number of elements in the first dimension.
Other potentially useful functions might be:-
'Return the number of dimensions in the array, 0 for an non-array.
Function CountDims(rvnt)
On Error Resume Next
Dim i : i = 0
Do While Err.Number = 0
i = i + 1
UBound rvnt, i
Loop
CountDims = i - 1
End Function
and :-
'Return the total number of elements across all dimensions
Function CountElements(rvnt)
On Error Resume Next
CountElements = 1
Dim i : i = 0
Do While Err.Number = 0
i = i + 1
CountElements = CountElements * (UBound(rvnt, i) - LBound(rvnt, i) + 1)
Loop
If i = 1 Then CountElements = 0
End Function
Hope you find this helpful,
--
Anthony Jones - MVP ASP/ASP.NET
<snip interesting dissertation on arrays>
> Hope you find this helpful,
Definitely interesting, however, perhaps not something one would use in
every day scripting. When a script creates and populates an array, the
knowledge required by the rest of the script to process that array is
generally implicit. The problem seems to arise when one's script receives a
variant result from a COM object or other "black box" source of data.
What your post does indicate very well, though, is that simple questions do
not necessarily always lead to simple answers, and also that we need to be
careful when mixing the "english" meaning of certain words such as "empty"
with what they might mean in the context of a scripting environment. That
was basically my intent for posting my little joke about trying to determine
if an array were half-empty or half full.
We have been discussing the complexities of determining whether or not an
array is "empty", perhaps without specifying which sense of the word we mean
(hence we may be thinking of different meanings). But surely the range of
meanings of various states of "non-emptiness" is even an even more thorny
one.
"full" is normally thought to mean that there is no more room for any
additional content. As applied to a vbscript array, this is practically
meaningless, as each element in an array could be assigned a higher value.
And once every element contained this value, the number of elements could be
increased with REDIM.
Yes, this is silly. But I think it illustrates that sometimes our problems
are mostly semantical.
/Al