Discussion:
Modifying array elements in a dictionary is ineffective?
(too old to reply)
JJ
2021-04-10 00:46:16 UTC
Permalink
There is no exception or error message. It doesn't matter whether the array
is fixed or variable length.

How could it happen?

Here's the code to reproduce the problem.

set dic = createobject("scripting.dictionary")
dic.add "key", array(1)
msgbox "initial = " & dic("key")(0)
dic("key")(0) = 5
msgbox "result = " & dic("key")(0) & " (should be 5)"
Mayayana
2021-04-10 03:05:26 UTC
Permalink
"JJ" <***@gmail.com> wrote

| There is no exception or error message. It doesn't matter whether the
array
| is fixed or variable length.
|
| How could it happen?
|
| Here's the code to reproduce the problem.
|
| set dic = createobject("scripting.dictionary")
| dic.add "key", array(1)
| msgbox "initial = " & dic("key")(0)
| dic("key")(0) = 5
| msgbox "result = " & dic("key")(0) & " (should be 5)"

Set dic = createobject("scripting.dictionary")
dic.add "key", Array(1)
MsgBox "initial = " & dic("key")(0)
A = dic("key")
A(0) = 5
dic("key") = A
MsgBox "result = " & dic("key")(0) & " (should be 5)"

I don't know the exact mechanics of this phenomenon,
but I've noticed in the past that in some or all cases, you
can't abstract multiple levels from an array. You have to access
the variable. I've never systematically tried to figure it out.
I just noticed over time that in some cases the pointers don't
seem to get through a multiple reference. In those cases I
add the extra step to access the variable directly before using it.
JJ
2021-04-10 10:08:43 UTC
Permalink
Post by Mayayana
Set dic = createobject("scripting.dictionary")
dic.add "key", Array(1)
MsgBox "initial = " & dic("key")(0)
A = dic("key")
A(0) = 5
dic("key") = A
MsgBox "result = " & dic("key")(0) & " (should be 5)"
I don't know the exact mechanics of this phenomenon,
but I've noticed in the past that in some or all cases, you
can't abstract multiple levels from an array. You have to access
the variable. I've never systematically tried to figure it out.
I just noticed over time that in some cases the pointers don't
seem to get through a multiple reference. In those cases I
add the extra step to access the variable directly before using it.
Your code changes the value in the dictionary item itself. Not just changing
the value contained in the dictionary item (which is the array). i.e. it
basically changes the whole array.

Even though that workaround works, it'll cause performace decrease for large
arrays because the array needs to be copied two times. But that can't be
helped, since it seems to be the only workaround.

My guess for problem, is due to the fact that the array or any value is
stored in a COM object instead of the script engine itself, because COM
properties can only have either `propget`, `propput`, and `propputref`.
There is no `propgetref`. And Dictionary COM doesn't expose any method which
can return the reference of an item's content. The script engine can not
know the direct reference of a property content because the property content
is managed by an external library.
Mayayana
2021-04-10 12:04:12 UTC
Permalink
"JJ" <***@gmail.com> wrote

| Your code changes the value in the dictionary item itself. Not just
changing
| the value contained in the dictionary item (which is the array). i.e. it
| basically changes the whole array.
|

No. It just gets a pointer to the array variable first,
rather than trying to do it in one step. The problem
seems to be that the array is not part of a dic object
model, so you can't reference it that way.

| Even though that workaround works, it'll cause performace decrease for
large
| arrays because the array needs to be copied two times. But that can't be
| helped, since it seems to be the only workaround.
|

It will probably slow things down. If you're doing something
big I wonder if a dictionary class could be better. I use them in
VB6. But everything's slow in VBS due to the constant data
conversion.

I do a similar thing to unpack MSI files and it works reasonably
well. I process all the data into an object model by using numerous
dictionaries to store it.

I assume you know you can access the items as a Keys array.
But of course that, not typically useful unless you just want to
walk the array. It defeats the purpose of accessing one item directly
by its keyy name.

| My guess for problem, is due to the fact that the array or any value is
| stored in a COM object instead of the script engine itself, because COM
| properties can only have either `propget`, `propput`, and `propputref`.
| There is no `propgetref`. And Dictionary COM doesn't expose any method
which
| can return the reference of an item's content. The script engine can not
| know the direct reference of a property content because the property
content
| is managed by an external library.

Sounds right. In other words, there's no object model.
With something like DOM you can have document.DivA(3).borderstyle,
but that's because the whole thing is an object model. The
variable pointer here is to the dictionary. Dictionary members
are not variables until you reference them. I hadn't thought of
it that way, but it makes sense.
R.Wieser
2021-04-10 08:39:13 UTC
Permalink
JJ,
Post by JJ
How could it happen?
Simples: the array is transferred "by value" into and outof the dictionary.

Don't ask me why though ...

set dic = createobject("scripting.dictionary")
arr = array(1)
dic.add "key", arr
wscript.echo "initial = " & dic("key")(0)
arr(0)=6
wscript.echo "result = " & dic("key")(0) & " (should be "& arr(0) &")"

Yup, noticed that some years ago ...

Regards,
Rudy Wieser
Mayayana
2021-04-11 19:41:42 UTC
Permalink
"JJ" <***@gmail.com> wrote

| There is no exception or error message. It doesn't matter whether the
array
| is fixed or variable length.
|

Thinking about this I was curious what you were trying
to accomplish. I've actually used arrays in dictionaries quite
a bit, but it's cases where I want to store a lot of data
about single items. For instance, it's efficient to name a key
for a file name, then have an array of file properties as the
data. It works well because it exploits the strength of a
dictionary: searching by unique ID. In that usage it's similar
to a database. If there's no relevant, unique key name then
multiple arrays would usually make more sense. For example,
array1 stores a number of random values that need to be
searched, while array2, or a second dimension, stores related
data. You can do something similar returning Dic.Keys as an
array. But I can't think of an example where I would need
to search through numerous arrays in a Dictionary, with no
guidance provided by the key name. That would be like
a database table with no column of unique values.
JJ
2021-04-12 02:13:28 UTC
Permalink
Post by Mayayana
Thinking about this I was curious what you were trying
to accomplish. I've actually used arrays in dictionaries quite
a bit, but it's cases where I want to store a lot of data
about single items. For instance, it's efficient to name a key
for a file name, then have an array of file properties as the
data. It works well because it exploits the strength of a
dictionary: searching by unique ID. In that usage it's similar
to a database. If there's no relevant, unique key name then
multiple arrays would usually make more sense. For example,
array1 stores a number of random values that need to be
searched, while array2, or a second dimension, stores related
data. You can do something similar returning Dic.Keys as an
array. But I can't think of an example where I would need
to search through numerous arrays in a Dictionary, with no
guidance provided by the key name. That would be like
a database table with no column of unique values.
My current use for it is to manage metadata of multiple files which can be
number, string, or binary. Some of the binary metadata are data
structure(s), so I need the ability to read/modify only part of the data,
instead of the whole data. The final use is for file lookup and bulk file
processing. i.e.:

FilesArray
-> FileInfoDictionary
-> FilePropertiesDictionary
-> Property
-> ...
-> FileMetadataDictionary
-> Metadata
-> ...
-> ...
Mayayana
2021-04-12 13:51:06 UTC
Permalink
"JJ" <***@gmail.com> wrote

| My current use for it is to manage metadata of multiple files which can be
| number, string, or binary. Some of the binary metadata are data
| structure(s), so I need the ability to read/modify only part of the data,
| instead of the whole data. The final use is for file lookup and bulk file
| processing. i.e.:
|
| FilesArray
| -> FileInfoDictionary
| -> FilePropertiesDictionary
| -> Property
| -> ...
| -> FileMetadataDictionary
| -> Metadata
| -> ...
| -> ...

I see. That is a tricky one. Have you considered an MSI file?
I use them for all kinds of things. Incredibly fast. They'll handle
string data, binary, and several numeric types. There are also
predefined types like Time/Date and GUID. Once you get the
process of loading them up and accessing them they're very
adaptable. It's sort of a stripped down SQL. MS calls it WQL,
for "Windows". The only hard part is the tedious syntax needed
for queries.

I use one for looking up ZIP codes. Another to store old email
in a searchable system with an HTA GUI frontend. I use one
to store location data for IP4 and IP6 addresses, so that I
can resolve an IP to location. I find them very useful as simple,
lightweight databases for VBS. And usually I write some kind of
HTA front-end.
JJ
2021-04-12 17:08:38 UTC
Permalink
Post by Mayayana
I see. That is a tricky one. Have you considered an MSI file?
That's kind of impractical for my application, because the user choose which
files to process. The combination of the files is likely to always change.
So at least for me, having to create a file for each application task
outweighs the performance benefit.

Loading...