Dictionary with arrays as values

I am trying to create a dictionary with arrays as the values. The dictionary has 30 keys and each key needs to have a 25 element array as it’s value. I’m using a temporary array to create the 25 elements and then setting the dictionary value to the array. However, when I empty the temporary array to build the next dictionary value, the array in the dictionary also gets emptied. I understand, now, that this is due to the dictionary array only containing a pointer to the array, but is there a way for the array elements to remain in the dictionary after resetting the temporary array.

Yes.

Please post your code and we’ll help you fix it.

You need to make new arrays each time, not resize.
Because when you put a reference to your array into the dictionary and then resize it, you only have one array, so you resize it.

1 Like

Code snippet below: temp_array() holds all the string values. I take 25 at a time, put those into the one_shot() array, then enter that array as the dictionary value. The first cycle works fine, but after I empty the one_shot() array, the corresponding dictionary value empties as well. Your help is greatly appreciated.

‘’’
Cycle through temp_array() and parse
counter = 0
key_index = 0

For Each line As String In temp_array

one_shot.add(line)
counter = counter + 1

If counter = 25 Then

webster.value(key_index) = one_shot()
counter = 0
key_index = key_index + 1
one_shot.RemoveAll

End If

Next
‘’’

Slightly refactor and create one_shot in a local context (warning: forum code… probably not optimal)

'Cycle through temp_array() and parse
var i as integer
key_index = 0

while i < temp_array.count
   var one_shot() as string   'declared within the scope of the while -- get a new one next loop
   counter = 0
   while counter<25 and i<temp_Array.count 'handles case where < 25 in final batch
     one_shot.add(temp_array(i))
     i = i + 1
     counter = counter + 1
   wend
   webster.value(key_index) = one_shot
   key_index = key_index + 1
wend

1 Like

When you assign an array, you are assigning a reference, not creating a copy. In your case, you are only manipulating one array that has multiple references, one_shot and all the values in the Dictionary. So when you clear one_shot, you are clearing the only array that exists.

This simple change will fix it.

If counter = 25 Then

  webster.value(key_index) = one_shot()
  counter = 0
  key_index = key_index + 1

  var empty() as string
  one_shot = empty

End If

That creates a brand new array, then points one_shot to it.

Remember to assign one_shot to the Dictionary too if there are any elements in it after the loop.

1 Like

Thanks Kem…works great! Can you tell me what Xojo is actually doing to leave the array in the dictionary? Is removing the pointer from one_shot to the array in the dictionary enough to make it work or is something else going on? Thanks, trying to better understand how Xojo implements certain functions.

This is something every Xojo coder struggles with initially.

Think of an array as you would an object like a Dictionary or DateTime. There is one in memory and you create references to it. The more variables you assign it to, the more references there are. By assigning that array to a Dictionary value (similar to assigning it to another variable), you create another reference to that array, but there is still just one array.

Example:

var a1() as string // One array at memory location XYZ
a1.Add "hi"

var a2() as string // Second, empty array at memory location ABC
a2.Add "ho"

a2 = a1 // The array at ABC loses it last reference and goes away, and a2 points to memory location XYZ

a2.Add "bingo"

// Now a1 and a2 point to the single array at XYZ that has two elements, "hi" and "bingo"

HTH.

1 Like

One other approach is to create a class which has an array as a property

Every item in the dictionary then becomes a
new MyArrayClass

which might help clarify matters.
Using new each time gets you a new object.
Each object has its own array

2 Likes

Jeff, I have not created a class before and am unfamiliar with how to go about it. Do you know of any video tutorials or other knowledge bases that explain how to design and implement a class structure? The info that I have found within the Xojo documentation doesn’t quite get me there. Appreciate it.

Hi.
Well, you USE classes all the time.
In a way, you can think of every window you add as a class.
You right click on it and can add properties , methods, and functions

A class works the same way.

But lets sneak up on it…

Imagine you have a car.
It has a make, model, and engine CC

You could create 3 variables for that.

CarMake as string
CarModel as string
CarCC as integer

If you need to deal with 10 cars, you might have thought:
CarMake(9) as string
CarModel(9) as string
CarCC(9) as integer

and to set up the first car

CarMake(0) = "Ford"
CarModel(0) = "Edsel"

etc

but better to group the variables together in a class.

To do that,
INSERT MENU/Class
It adds Class1

In the properties, rename Class1 as objCar
Now, like a window, we can add properties
So right click on the class and ‘Add to objCar’ … Property

Add Make as String
Add Model as string
(you already know that for your original purpose this would be something(24) as string, right?)
EngineCC as integer

So, now you have a class!

In code, try this:

objCar.Make = "Ford"

It will fail to run. Because unlike an integer or double, Xojo hasnt made a memory allocation for it yet.

Instead you must do this:

Dim MyCar as new objCar
MyCar.Make = "Nissan"
MyCar.Model = "Juke"
MyCar.EngineCC = 1600

to get them into a dictionary:


Dim CarDictionary as new Dictionary
Dim SomeCar as objCar
SomeCar = new objCar
SomeCar.Make = "Nissan"
SomeCar.Model = "Juke"
SomeCar.EngineCC = 1600
CarDictionary.value ("CarRegistration1") = SomeCar

SomeCar = new objCar
SomeCar.Make = "Ford"
SomeCar.Model = "Edsel"
SomeCar.EngineCC = 100
CarDictionary.value ("CarRegistration2") = SomeCar
..and so on

You Class will have an array of strings as a property.
(It may instead have named strings like my car, if that array actually contained things like an address)

Once you have a class you can add methods to it…for example you could add a method that sets all the strings to say “custard”
Or add up the values of some numbers, or…

Hope that helps for now.

2 Likes

Using the original example…(although now I read this I am not actually sure why you chop temp_array into many smaller arrays…)

//Cycle through temp_array() and parse
counter = 0
key_index = 0

dim This25lineArray as new obj25lineArray  //a class

For Each line As String In temp_array
This25lineArray.value(counter) = line
counter = counter + 1
If counter = 24 Then  //we have filled one up with 25 values
webster.value(key_index) = This25lineArray
counter = 0
key_index = key_index + 1
This25lineArray = new obj25lineArray
End If

Next
1 Like

If you have fixed sizes… Why dont you use a multidimentional array?

1 Like

Thanks Ivan. The dictionary arrays I’m creating will have multiple types of calculations performed on the elements of the array and then compare them to the other arrays in the dictionary. I will end up with various other arrays to track the comparisons.

Thanks Jeff. The temp_array is part of a vanilla template that I use to read in text files with multiple lines of string values. It’s just easier for me to get the data file open and shut and then deal with the parsing as a secondary. The text files change depending on the project.
I’ll work on incorporating the class structure and see how it works. I appreciate you taking the time to help nudge me along.

They are immeasurably useful. The thing I had to get over was the mindset that creating a class was a Serious Endeavor, and that The Class had to be finely crafted and passed down to generations of future programmers. That can be the case if you’re making, say a new control that might be useful to others. But in fact, classes are something you can (and should) just toss together all the time as part of your everyday programming, as a way to encapsulate related properties and methods. For example, if you’re writing an app to do with cars, just make a Car class. You don’t set its super to anything, it’s just an abstract object. Now give it some properties, like color, make, model, number of doors, horespower, whatever. Add a constructor method with parameters like color, make, model, etc. so you can make a new car object using New and some parameters. Now if you have a method that does something with a car, you can just pass a car object as a parameter to that method instead of having to pass all the properties of the car separately. Or you can add methods to the Car class that allow it to do things to itself, so you have the more self-contained MyCar.Recharge instead of Recharge(MyCar). When you need to store a bunch of cars, you’ll make an array of cars, instead of a bunch of arrays storing car properties.

Once you get the hang of this, you’ll find that your programs will have more and more structures (arrays, dictionaries, etc) containing objects of your own design and fewer structures of less-meaningful intrinsic types, which makes your programs more concise, more readable and more powerful.

4 Likes

About arrays:

I agree with Julia. Years ago someone (I think it was Norm) advised to use classes unless you absolutely can’t. Example is structs: they can hold a variety of datatypes too, but are mainly useful if you need to pass data to the OS via a declare. Otherwise the same can (and should) be accomplished with classes, which is what I always now use classes for collections of data, even very simple ones, and it has made life much easier. And then methods can do custom operations on that data, all in a neat package.

3 Likes