I have the following classes:
Class Person
Property ID As String = Nothing
Property Firstname As String = ""
Property Lastname As String = ""
End Class
Class Account
Property AccountNumber As String = ""
Property Owners As New List(Of Person)
End Class
Using Bogus, I set a range of values from 1,000 to 10,000 for Person.ID, like so:
Dim fakePerson = New Faker(Of Person)().
StrictMode(False).
Rules(Sub(c, p)
p.ID = c.Random.Long(1000, 10000).ToString
End Sub
)
How do I set Account.Owners to utilize Person.ID values as defined in fakePerson when I instantiate an instance of the Account class like so?:
Dim fk = Faker.Create()
Dim acct = fk.Generate(Of Account)
Solution provided by Bogus author bchavez at https://github.com/bchavez/Bogus/issues/394.
Sub Main
Dim personFaker = New Faker(Of Person)
personFaker.RuleFor(Function(p) p.Firstname, Function(f) f.Name.FirstName)
.RuleFor(Function(p) p.Lastname, Function(f) f.Name.LastName)
.RuleFor(Function(p) p.ID, Function(f) f.Random.Int(1000,10000).ToString)
Dim accountFaker = New Faker(Of Account)
accountFaker.RuleFor(Function(a) a.AccountNumber, Function(f) f.Random.Replace("###############"))
.RuleFor(Function(a) a.Owners, Function(f) New List(Of Person)(personFaker.GenerateBetween(1,5)))
accountFaker.Generate().Dump()
End Sub
Class Person
Property ID As String = Nothing
Property Firstname As String = ""
Property Lastname As String = ""
End Class
Class Account
Property AccountNumber As String = ""
Property Owners As New List(Of Person)
End Class
Related
i have this class and i am trying to make a class constructor or factory method (not sure how's the right name in VBA). When i try to run it i get a dialog with written debug error, and ig highlights the set row of the test module. What's wrong? What is the right way to instantiate the collection in the constructor? is it better to use the keyword this when using let/get ?
Class Address
Private pStreet As String
Private pZip As Integer
Public Property Let Street(val As String)
pStreet = val
End Property
Public Property Get Street() As String
Street = pStreet
End Property
Public Property Let Zip(val As Integer)
pZip = val
End Property
Public Property Get Zip() As Integer
Zip = pZip
End Property
Class Person
Private pName As String
Private pSurname As String
Private pAddresses As New Collection
Public Property Let Name(val As String)
pName = val
End Property
Public Property Get Name() As String
Name = pName
End Property
Public Property Let Surname(val As String)
pSurname = val
End Property
Public Property Get Surname() As String
Surame = pSurname
End Property
Private Sub Class_Initialize()
Set pAddresses = New Collection
End Sub
Private Sub Class_Terminate()
Set pAddresses = Nothing
End Sub
Public Sub addAddress(ByVal val As Address)
pAddresses.Add val
End Sub
Public Property Get Addresses() As Collection
Set Addresses = pAddresses
End Property
Public Property Get Address(ByVal Index As Long) As Address
Set Address = pAddresses(Index)
End Property
Public Function CreatePerson(ByVal Name As String, ByVal Surname As String) As Person
With New Person
.pName = Name
.pSurname = Surname
Set CreatePerson = .Self
instance
End With
End Function
test Module
sub test()
Dim x as Person
Set x = Person.CreatePerson("Mike","Jordan")
end sub
Another option for creating a factory method is to use another class:
PersonFactory Class
Option Explicit
Public Function Create(ByVal Name As String, ByVal Surname As String, ByVal Street As String, ByVal Zip As Integer) As Person
Dim a As Address
Set Create = New Person
Create.Name = Name
Create.Surname = Surname
Set a = New Address
a.Street = Street
a.Zip = Zip
Create.Addresses.Add a
End Function
Test Module
Private Sub Test()
Dim pf As PersonFactory
Dim p As Person
Set pf = New PersonFactory
Set p = pf.Create("Mike", "Jordan", "my street", 11111)
End Sub
You have several errors
Your anonymous new is for GiantCorp and Not Person
You have no self method to return the Me Instance created by the With New Person
3 No idea what 'instance' is doing.
Your address class does not manage a collection of addresses, nor does you person class
Here is updated code for your person class. Don't feel too bad, Factory classes in VBA are actuall a tricky subject when you first encounter them.
Option Explicit
'#PredecalredId
'#exposed
Private Type Properties
Name As String
Surname As String
Address As Address
End Type
Private p As Properties
Public Property Let Name(ipName As String)
p.Name = ipName
End Property
Public Property Get Name() As String
Name = p.Name
End Property
Public Property Let Surname(ipSurname As String)
p.Surname = ipSurname
End Property
Public Property Get Surname() As String
Surame = p.Surname
End Property
' This property will fail as the Address class is not a collection
Public Sub addAddress(ipAddress As Address)
Set p.Address = ipAddress
End Sub
Public Function CreatePerson(ByVal ipName As String, ByVal ipSurname As String) As Person
With New Person 'GiantComp no idea what this GiantComp' class is doing here
' Private fields cannot be accessed here, you need to forward them to the self function
'.pName = ipName
'.pSurname = ipSurname
Set CreatePerson = .Self(ipName, ipSurname)
End With
End Function
Public Function Self(ByVal ipName As String, ByVal ipSurname As String) As Person
' You are now inside the anonymous Person class you created with 'With nEw Person' so you can now access private fields
p.Name = ipName
p.Surname = ipSurname
Set Self = Me
End Function
You will also need to set the PredeclaredId attribute. This involves either exporting you class, editing the relevant attribute and reimporting, or, much more conveniently, using the attribute annotation '#PredecaredId provided by the free and fantastic Rubberduck add in for VBA.
Good luck in creating an addresses collection class to manage you addresses. Lots of examples are available of how to wrap a collection to produce a collection class.
I'm learning about storing multiple values for a Key in VBA. My research has lead to me to utilize a custom Collection Class.
I got it to work in theory and then in practice I wanted to look up values based on the key but was only able to do it via "index number". I then generated a Property to return that index number, but that means if I have to loop through Keys each each will loop through the entire collection to find the index number before moving forward. This seems like too much computation and I'm wondering if there is a way to use a dicitonary key/value setup to store the Keys Index and have this all setup inside the Collection Class so I can directly call a keys value via it's index from the dictionary.
Here is my code so far:
Module:
'https://www.wiseowl.co.uk/blog/s239/collections.htm
Sub CreatePeople()
Dim p1 As New clsPersons, p2 As New clsPersons, p3 As New clsPersons
With p1
.FirstName = "Rita"
.LastName = "Smith"
End With
With p2
.FirstName = "Sue"
.LastName = "Jones"
End With
With p3
.FirstName = "Bob"
.LastName = "Brown"
End With
Debug.Print p1.FirstName, p1.LastName, p1.FullName
Debug.Print p1.FullName, p2.FullName, p3.FullName
End Sub
Sub CreatePersonsCollectionSafer()
Dim Persons As New clsPersons
Persons.Add "Rita", "Smith"
Persons.Add "Sue", "Jones"
Persons.Add "Bob", "Brown"
Dim Person As clsPersons
Dim PersonNumber As Integer
Debug.Print Persons.Count
For PersonNumber = 1 To Persons.Count
Debug.Print Persons.Item(PersonNumber).FullName
Next PersonNumber
Dim LastName As String
LastName = "Brown"
Debug.Print "Last Name = " & LastName & " & First Name = " & Persons.ItemByLastName(LastName).FirstName
End Sub
Class (clsPersons):
Option Explicit
Private Persons As New Collection
Private Person As clsPersons
Public FirstName As String
Public LastName As String
''Subs
Sub Add(FirstName As String, LastName As String)
Dim p As New clsPersons
p.FirstName = FirstName
p.LastName = LastName
Persons.Add p
End Sub
Sub Remove(NameOrNumber As Variant)
Persons.Remove NameOrNumber
End Sub
''EndSubs
''Properties
Property Get Count() As Long
Count = Persons.Count
End Property
Property Get Item(Index As Variant) As clsPersons
Set Item = Persons(Index)
End Property
Property Get FullName() As String
FullName = FirstName & " " & LastName
End Property
Property Get Items() As Collection
Set Items = Persons
End Property
Property Get ItemByLastName(LastName As String) As clsPersons
Dim PersonsIndex As Integer
For PersonsIndex = 1 To Persons.Count
Debug.Print Persons.Item(PersonsIndex).LastName
If Persons.Item(PersonsIndex).LastName = LastName Then
Set ItemByLastName = Persons(PersonsIndex)
Exit For
End If
Next PersonsIndex
End Property
''EndProperties
You should be using the keys provided by the collection. You don't need an extra collection/dictionary.
Sub Add(FirstName As String, LastName As String)
Dim p As New clsPersons
p.FirstName = FirstName
p.LastName = LastName
Persons.Add p, LastName
End Sub
Property Get ItemByLastName(LastName As String) As clsPersons
Set ItemByLastName = Persons(LastName)
End Property
However, you should not be working with a single class here. You are basically holding a new collection of persons inside each person. You should have a Person and a Persons class to make code easier to read and maintain.
You should also hide your members and expose getters to achieve encapsulation. In your code you can easily change the name of a person and thus the keys will be useless.
Here is a different approach:
Person class:
Option Explicit
Private m_firstName As String
Private m_lastName As String
Private m_initialized As Boolean
Public Function Init(ByVal firstName_ As String, ByVal lastName_ As String) As Boolean
If m_initialized Then
Err.Raise 5, TypeName(Me) & ".Init", "Already initialized"
End If
If firstName_ = vbNullString Or lastName_ = vbNullString Then Exit Function 'Returns False
m_firstName = firstName_
m_lastName = lastName_
m_initialized = True
Init = True
End Function
Property Get FirstName() As String
FirstName = m_firstName
End Property
Property Get LastName() As String
LastName = m_lastName
End Property
Property Get FullName() As String
FullName = m_firstName & " " & m_lastName
End Property
Public Function Self() As Person
Set Self = Me
End Function
Persons class:
Option Explicit
Private m_persons As New Collection
Public Function Add(ByVal p As Person) As Boolean
On Error Resume Next 'Name can already exist
m_persons.Add p, p.LastName 'Or maybe full name would be better as multiple persons can share the same last name
Add = Err.Number = 0
On Error GoTo 0
End Function
Public Function AddFromValues(ByVal firstName_ As String, ByVal lastName_ As String) As Boolean
With New Person
If Not .Init(firstName_, lastName_) Then Exit Function
AddFromValues = Me.Add(.Self)
End With
End Function
Public Sub Remove(ByVal indexOrLastName As Variant)
m_persons.Remove indexOrLastName
End Sub
Public Property Get Count() As Long
Count = m_persons.Count
End Property
Property Get Item(ByVal indexOrLastName As Variant) As Person
Set Item = m_persons(indexOrLastName)
End Property
Property Get Items() As Collection
Set Items = m_persons
End Property
Public Function Exists(ByVal lastName_ As String) As Boolean
On Error Resume Next
m_persons.Item lastName_
Exists = (Err.Number = 0)
On Error GoTo 0
End Function
and then the testing code in a standard .bas module:
Option Explicit
Public Sub CreatePeople()
Dim p1 As New Person
Dim p2 As New Person
Dim p3 As New Person
p1.Init "Rita", "Smith"
p2.Init "Sue", "Jones"
p3.Init "Bob", "Brown"
Debug.Print p1.FirstName, p1.LastName, p1.FullName
Debug.Print p1.FullName, p2.FullName, p3.FullName
End Sub
Public Sub CreatePersonsCollectionSafer()
Dim myPersons As New Persons
myPersons.AddFromValues "Rita", "Smith"
myPersons.AddFromValues "Sue", "Jones"
myPersons.AddFromValues "Bob", "Brown"
Dim tempPerson As Person
For Each tempPerson In myPersons.Items
Debug.Print tempPerson.FullName
Next tempPerson
Dim lastNameToSearch As String
lastNameToSearch = "Brown"
Debug.Print "Last Name = " & lastNameToSearch & " & First Name = " _
& myPersons.Item(lastNameToSearch).FirstName
End Sub
I've solved this issue via the following:
Private PersonsIndexDic As Object
Sub Add(FirstName As String, LastName As String)
Dim p As New clsPersons
p.FirstName = FirstName
p.LastName = LastName
Persons.Add p
PersonsIndexDic.Add Key:=LastName, Item:=PersonsIndexDic.Count + 1
End Sub
Property Get ItemByLastName(LastName As String) As clsPersons
Set ItemByLastName = Persons(PersonsIndexDic(LastName))
End Property
Test:
Dim LastName As String
LastName = "Brown"
Debug.Print "Last Name = " & LastName & " & First Name = " & Persons.ItemByLastName(LastName).FirstName
I'm trying to create a Staff class module, with strings for surname etc, and an arraylist to be used for storing / calling between 0-10 strings dependant on how many are added when used.
The class module is called StaffClass and contains:
Private m_surname As String
Private m_districts as ArrayList
' Surname Prop
Property Get surname() As String
surname = m_surname
End Property
Property Let surname(surname As String)
m_surname = Name
End Property
' District Prop
' This is where i'm getting confused
Private Sub Class_ArrList()
Set m_districts = New ArrayList
End Sub
Property Get districts() As ArrayList
districts = m_districts
End Property
Property Let districts(districts as ArrayList)
m_districts = districts
End Property
The Main Module contains:
Dim newStaff As StaffClass
Set newStaff = New StaffClass
newStaff.surname = "Smith"
' This is where I want to add to the arraylist
newStaff.districts(0) = "50"
I'm aware I'm missing loads, but struggling to find much relating to collections inside classes for VBA.
Hoping you can help!
You can put the arraylist initialization routine in a Class_Initialize, and add a methods to the class to add/insert/etc each item. (Or you could add a method to add the arraylist as a single object).
Also, since ArrayList is an object, you'll need to use the Set keyword when retrieving it.
eg:
Class module
Option Explicit
Private m_surname As String
Private m_districts As ArrayList
' Surname Prop
Property Get surname() As String
surname = m_surname
End Property
Property Let surname(surname As String)
m_surname = surname
End Property
Property Get districts() As ArrayList
Set districts = m_districts
End Property
Function addDistrict(Value As String)
m_districts.Add Value
End Function
Private Sub Class_Initialize()
Set m_districts = New ArrayList
End Sub
Regular Module
Option Explicit
Sub par()
Dim newStaff As StaffClass
Dim V As ArrayList
Set newStaff = New StaffClass
With newStaff
.surname = "Smith"
.addDistrict 50
.addDistrict "xyz"
End With
Set V = newStaff.districts
Stop
End Sub
I am trying to loop over the items in a dictionary with an object variable that refer to inheritance class "Breed", but I am unable to do so with dictionaries but with collections it is pretty simple is there a way to solve this without using the dictionary's keys? because then I will lose the ability to use the intelisense feature.
Here is the code of the class Breed:
Option Explicit
Public Property Get Name() As String
End Property
Public Property Get Color() As String
End Property
Public Property Get Price() As Double
End Property
Here is the code for class Dogs:
Option Explicit
Implements Breed
Private pName As String, pPrice As Double, pColor As String
Public Property Let Name(Val As String)
pName = Val
End Property
Public Property Get Name() As String
Name = pName
End Property
Private Property Get Breed_Name() As String
Breed_Name = Name
End Property
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Property Let Price(Val As Double)
pPrice = Val
End Property
Public Property Get Price() As Double
Price = pPrice
End Property
Private Property Get Breed_Price() As Double
Breed_Price = Price
End Property
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Property Let Color(Val As String)
pColor = Val
End Property
Public Property Get Color() As String
Color = pColor
End Property
Private Property Get Breed_Color() As String
Breed_Color = Color
End Property
Here is the code for class Cats:
Option Explicit
Implements Breed
Private pName As String, pPrice As Double, pColor As String
Public Property Let Name(Val As String)
pName = Val
End Property
Public Property Get Name() As String
Name = pName
End Property
Private Property Get Breed_Name() As String
Breed_Name = Name
End Property
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Property Let Price(Val As Double)
pPrice = Val
End Property
Public Property Get Price() As Double
Price = pPrice
End Property
Private Property Get Breed_Price() As Double
Breed_Price = Price
End Property
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Property Let Color(Val As String)
pColor = Val
End Property
Public Property Get Color() As String
Color = pColor
End Property
Private Property Get Breed_Color() As String
Breed_Color = Color
End Property
Here is the code for the regular module with collection but fails with dictionary:
Option Explicit
Sub Main()
Dim C As Cats
Dim D As Dogs
Dim Coll As Collection
Dim B As Breed
Set C = New Cats
C.Name = "Catomon"
C.Color = "Angle White"
C.Price = 800.98
Set D = New Dogs
D.Name = "Dogomon"
D.Color = "Golden White"
D.Price = 1000.23
Set Coll = New Collection
Coll.Add C
Coll.Add D
Set B = New Breed
For Each B In Coll
Debug.Print B.Name, B.Color, B.Price
Next B
Set C = Nothing
Set D = Nothing
Set B = Nothing
Set Coll = Nothing
End Sub
Dictionary methods .Keys() and .Items() return arrays. Only way to iterate over arrays is with an variable of type Variant. With these restrictions, the only way I can think of is casting Variant variable to the type Breed inside the loop. This way, after the casting, you get Intellisense.
Based on the code you posted, an example would be:
Sub MainWithDictionary()
Dim C As Cats
Dim D As Dogs
Dim Dict As Scripting.Dictionary
Dim B As Breed
Dim K As Variant 'new variable
Set C = New Cats
C.Name = "Catomon"
C.Color = "Angle White"
C.Price = 800.98
Set D = New Dogs
D.Name = "Dogomon"
D.Color = "Golden White"
D.Price = 1000.23
Set Dict = New Scripting.Dictionary
'Keys are just placeholders
Dict.Add 1, C
Dict.Add 2, D
For Each K In Dict.Items()
'Cast the Variant result to Breed
Set B = K
'You will have Intellisense on each dictionary items after this
Debug.Print B.Name, B.Color, B.Price
Next K
Set C = Nothing
Set D = Nothing
Set B = Nothing
Set Dict = Nothing
End Sub
I've been reading this topic on how to use class modules.
My goal is to improve my code performance and readability so I think I'm in the right path.
But I have some questions about the limitations.
In my head i want to do this:
Is it possible to achieve such a structure?
The topic I've read has very few examples and this is not handled. I'm assuming this would be possible with collections of collections, but I not sure how to look for this.
My data comes from 2 tables, one has all the items but the department and the other one has the ID's alongisde the departments. Both tables have the dates of the current month as headers and their Schedule/Department depending on the table.
I'd know how to achieve this for one day, but not for a whole month.
This is how I wrote the basics for my class:
Option Explicit
Private DirNeg As String
Private Agrup As String
Private DNI As String
Private Centro As String
Private Servicio As String
Private Nombre As String
Property Get Business() As String
Business = DirNeg
End Property
Property Let Business(ByVal sBusiness As String)
DirNeg = sBusiness
End Property
Property Get Group() As String
Group = Agrup
End Property
Property Let Group(ByVal sGroup As String)
Agrup = sGroup
End Property
Property Get ID() As String
ID = DNI
End Property
Property Let ID(ByVal sID As String)
DNI = sID
End Property
Property Get Location() As String
Location = Centro
End Property
Property Let Location(ByVal sLocation As String)
Centro = sLocation
End Property
Property Get Service() As String
Service = Servicio
End Property
Property Let Service(ByVal sService As String)
Servicio = sService
End Property
Property Get Name() As String
Name = Nombre
End Property
Property Let Name(ByVal sName As String)
Nombre = sName
End Property
On the other hand, is it correct to fill the whole class on the Class_Initializeevent? My data will always be the same so I don't need to loop in a normal module to fill the class, it could be done everytime the class is created.
EDIT/UPDATE:
This is how my data looks like:
Schedules alongside Agent's info
Departments alongside Agent's ID
clAgent Class Module:
Option Explicit
Private DirNeg As String
Private Agrup As String
Private DNI As String
Private Centro As String
Private Servicio As String
Private Nombre As String
Private Fechas As Object
Property Get Business() As String
Business = DirNeg
End Property
Property Let Business(ByVal sBusiness As String)
DirNeg = sBusiness
End Property
Property Get Group() As String
Group = Agrup
End Property
Property Let Group(ByVal sGroup As String)
Agrup = sGroup
End Property
Property Get ID() As String
ID = DNI
End Property
Property Let ID(ByVal sID As String)
DNI = sID
End Property
Property Get Location() As String
Location = Centro
End Property
Property Let Location(ByVal sLocation As String)
Centro = sLocation
End Property
Property Get Service() As String
Service = Servicio
End Property
Property Let Service(ByVal sService As String)
Servicio = sService
End Property
Property Get Name() As String
Name = Nombre
End Property
Property Let Name(ByVal sName As String)
Nombre = sName
End Property
Property Get clFechas(ByVal StringKey As String) As clFechas
With Fechas
If Not .Exists(StringKey) Then
Dim objFechas As New clFechas
.Add StringKey, objFechas
End If
End With
End Property
Private Sub Class_Initialize()
Set Fechas = CreateObject("Scripting.Dictionary")
End Sub
clFechas Class Module:
Option Explicit
Private Modos As Object
Private Horarios As Object
'Aqiço creamos la propiedad Modo para la clase Fecha
Public Property Get Modo(ByVal StringKey As String) As String
Modo = Modos(StringKey)
End Property
Public Property Let Modo(ByVal StringKey As String, ByVal StringValue As String)
Modos(StringKey) = StringValue
End Property
Public Property Get Keys() As Variant
Keys = Modos.Keys
End Property
'Aquí creamos la propiedad Horario para la clase Fecha
Public Property Get Horario(ByVal StringKey As String) As String
Modo = Horarios(StringKey)
End Property
Public Property Let Horario(ByVal StringKey As String, ByVal StringValue As String)
Horarios(StringKey) = StringValue
End Property
Public Property Get Keys() As Variant
Keys = Horarios.Keys
End Property
'Iniciamos la clase
Private Sub Class_Initialize()
Set Modos = CreateObject("Scripting.Dictionary")
Set Horarios = CreateObject("Scripting.Dictionary")
End Sub
Private Sub Class_Terminate()
Set Modos = Nothing
Set Horarios = Nothing
End Sub
You don’t seem to have any issues with regular properties so let’s focus on the complex ones; Schedule and Department. Both are the same, so same rules apply to both.
The property is basically list, the date is the index and the item is an object. I personally prefer to work with dictionaries as I can look if a key exist etc.
So, your Agent class could look something like this:
Option Explicit
Private m_schedules As Object
Public Property Get Schedule(ByVal Key As Date) As Schedules
With m_schedules
If Not .Exists(Key) Then .Add Key, New Schedules
End With
Set Schedule = m_schedules(Key)
End Property
'For testing purposes - can be ommited.
Public Property Get Keys() As Variant
Keys = m_schedules.Keys
End Property
'For testing purposes - can be ommited.
Public Property Get Count() As Long
Count = m_schedules.Count
End Property
Private Sub Class_Initialize()
Set m_schedules = CreateObject("Scripting.Dictionary")
End Sub
Private Sub Class_Terminate()
Set m_schedules = Nothing
End Sub
The Schedules class:
Option Explicit
Private m_schedule As String
Public Property Get Schedule() As String
Schedule = m_schedule
End Property
Public Property Let Schedule(ByVal param As String)
m_schedule = param
End Property
Now, let's test it:
Sub Test()
Dim obj As Agent
Set obj = New Agent
obj.Schedule(#1/9/2019#).Schedule = "Schedule 1"
obj.Schedule(#2/9/2019#).Schedule = "Schedule 2"
obj.Schedule(#3/9/2019#).Schedule = "Schedule 3"
PrintToDebug obj
'Lets make a change
obj.Schedule(#2/9/2019#).Schedule = "Schedule 2222"
PrintToDebug obj
End Sub
Private Sub PrintToDebug(ByVal obj As Agent)
Debug.Print ""
Dim m As Variant
With obj
For Each m In .Keys
Debug.Print "Key: " & m & String(3, " ") & "Value: " & .Schedule(m).Schedule
Next m
End With
Debug.Print "Total Items: " & obj.Count
End Sub
Output:
'Key: 09/01/2019 Value: Schedule 1
'Key: 09/02/2019 Value: Schedule 2
'Key: 09/03/2019 Value: Schedule 3
'Total Items: 3
'Key: 09/01/2019 Value: Schedule 1
'Key: 09/02/2019 Value: Schedule 2222
'Key: 09/03/2019 Value: Schedule 3
'Total Items: 3
Additional information regarding the Dictionary object can be found here: Dictionary object
Also keep this in mind. It's quite important:
If key is not found when changing an item, a new key is created with
the specified newitem. If key is not found when attempting to return
an existing item, a new key is created and its corresponding item is
left empty.
If the dictionary item is not a simple string, let me know to update the answer. Sorry, I couldnt read the data in the screenshots. :)