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.
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.
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
counter = counter + 1
If counter = 25 Then
webster.value(key_index) = one_shot() counter = 0 key_index = key_index + 1 one_shot.RemoveAll
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
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.
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.
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"
One other approach is to create a class which has an array as a property
Every item in the dictionary then becomes a
which might help clarify matters.
Using new each time gets you a new object.
Each object has its own array
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.
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"
but better to group the variables together in a class.
To do that,
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.
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
If you have fixed sizes… Why dont you use a multidimentional array?
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.
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.