Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Putting dictionaries into classes

Tags:

excel

vba

I was given an answer on how to make a general class module: Class "let" stuck in infinite loop

I'm trying to apply this to dictionaries inside my classes.

My class module:

Option Explicit

Private Type categories
    Temp As scripting.Dictionary
    Humid As scripting.Dictionary
    Wind As scripting.Dictionary
End Type

Private this As categories

Public Sub Initialize()
    Set this.Temp = New scripting.Dictionary
    Set this.Humid = New scripting.Dictionary
    Set this.Wind = New scripting.Dictionary
End Sub

Public Property Get Temp(ByVal HourIndex As Long) As Double
    Temp = this.Temp(HourIndex)
End Property

Public Property Let Temp(ByVal HourIndex As Long, ByVal Value As Double)
    this.Temp(HourIndex) = Value
End Property

Public Property Get Humid(ByVal HourIndex As Long) As Double
    Humid = this.Humid(HourIndex)
End Property

Public Property Let Humid(ByVal HourIndex As Long, ByVal Value As Double)
    this.Humid(HourIndex) = Value
End Property

Public Property Get Wind(ByVal HourIndex As Long) As Double
    Wind = this.Wind(HourIndex)
End Property

Public Property Let Wind(ByVal HourIndex As Long, ByVal Value As Double)
    this.Wind(HourIndex) = Value
End Property

I tried to test this in the immediate window with set tester = new WeatherData (the name of the module) and Initialize. That did not work.

I then modified Initialize:

Public Sub Initialize(ByVal variable As categories)
    Set variable.Temp = New scripting.Dictionary
    Set variable.Humid = New scripting.Dictionary
    Set variable.Wind = New scripting.Dictionary
End Sub

and entered Initialize tester, but this did not work either ("Compile Error: Sub or Function not defined").

How do I put three dictionaries in a class module?

The following doesn't solve the problem, but it did skirt around it to the point that I don't have to acknowledge it:

Option Explicit

Private Type categories
    Temp(23) As Double
    Humid(23) As Double
    wind(23) As Double
End Type

Private this As categories

Public Property Get Temp(ByVal HourIndex As Long) As Double
    Temp = this.Temp(HourIndex)
End Property

Public Property Let Temp(ByVal HourIndex As Long, ByVal Value As Double)
    this.Temp(HourIndex) = Value
End Property

Public Property Get Humid(ByVal HourIndex As Long) As Double
    Humid = this.Humid(HourIndex)
End Property

Public Property Let Humid(ByVal HourIndex As Long, ByVal Value As Double)
    this.Humid(HourIndex) = Value
End Property

Public Property Get wind(ByVal HourIndex As Long) As Double
    wind = this.WindChill(HourIndex)
End Property

Public Property Let wind(ByVal HourIndex As Long, ByVal Value As Double)
    this.wind(HourIndex) = Value
End Property

tl;dr: make arrays instead of dictionaries, and cut out initialize entirely. Your "keys" have no choice but to be numbers, but it works. I would be interested in knowing an actual solution, but the specific issue is solved.

like image 708
kumquatwhat Avatar asked Apr 06 '17 17:04

kumquatwhat


People also ask

How do you convert a dictionary to a class?

We are calling a function here Dict2Class which takes our dictionary as an input and converts it to class. We then loop over our dictionary by using setattr() function to add each of the keys as attributes to the class. setattr() is used to assign the object attribute its value.

Can you put a dictionary in a class Python?

If you want to use a dictionary globally within a class, then you need to define it in section where you use your class. if you are using your class in main, then define it there. A dictionary or o list are global by default. class Store: ...

Should I use a dictionary or a class?

Classes are for bundling related data (and usually code). Dictionaries are for storing key-value relationships, where usually the keys are all of the same type, and all the values are also of one type.

Can a dictionary value be a class?

Is it possible to set a dictionary value to a class? Yes, it's possible.


1 Answers

Seems you want to implement an indexed property.

Simplified to a bare minimum:

Option Explicit
Private values As Scripting.Dictionary

Private Sub Class_Initialize()
    Set values = New Scripting.Dictionary
End Sub

Public Property Get Something(ByVal key As String) As Double
    Something = values(key)
End Property

Public Property Let Something(ByVal key As String, ByVal value As Double)
    values(key) = value
End Property

You keep the dictionaries safely encapsulated as an implementation detail of your class (external code cannot set them to Nothing, for example), and expose an indexed Get+Let property for each encapsulated dictionary, that takes the index (/key) as a parameter.

In the case of your WeatherData class, this means you can populate the data like this:

Set data = New WeatherData
With data
    .Temp("day 1") = 76
    .Temp("day 2") = 78
    .Humid("day 1") = 0.55
    .Humid("day 2") = 0.61
    .Wind("day 1") = 0.92
    .Wind("day 2") = 1.27
End With

And then retrieve the temperature of "day 1" with data.Temp("day 1").

As for your initializer method, it needed to be called from an instance of the class - being an instance method.

So instead of Initialize tester you should have done tester.Initialize.

Whether you make the internal encapsulated storage an array, a Collection or a Dictionary makes no difference to the calling code - it's an encapsulated implementation detail: your class could just as well store the data in .csv files or into a database if it wanted.

like image 117
Mathieu Guindon Avatar answered Sep 28 '22 06:09

Mathieu Guindon