Update() dictionary method?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Maverik
:warning: Old Version Published before Godot 3 was released.
var dictionary = {1 = 2, 3 = 4}
var new_element = {5 = 6, 7 = 8}
dictionary.update(new_element) (??)

Is there a way to add new elements to the existing dictionary I’m missing?

:bust_in_silhouette: Reply From: txzeenath
dictionary[5] = 6
dictionary[7] = 8


var dict = {A=1,B=2,C=3}
dict['D'] = 4
dict['E'] = 5
print(dict)
>> (A:1), (B:2), (C:3), (D:4), (E:5)

I don’t believe godot has a dictionary merge method.

Thats kind of a shame. Manual input step by step is not exactly optimal for me.

Maverik | 2016-09-16 12:18

Honestly, I don’t think GDScript needs to expose that just for the sake of economizing two lines. You can update the dictionary with just this:

static func merge_dir(target, patch):
	for key in patch:
		target[key] = patch[key]

Zylann | 2016-09-16 12:22

That actually helps, thank you.

Maverik | 2016-09-16 12:33

On the other note, it does not quite work when merging dictionaries have same subdictionaries.

Maverik | 2016-09-16 20:25

This version should work with sub-dictionaries:

static func merge_dir(target, patch):
	for key in patch:
		if target.has(key):
			var tv = target[key]
			if typeof(tv) == TYPE_DICTIONARY:
				merge_dir(tv, patch[key])
			else:
				target[key] = patch[key]
		else:
			target[key] = patch[key]

Zylann | 2016-09-16 20:35

Yep, seems to be working, except for has_key should be just key. Thank you!

Maverik | 2016-09-16 20:56

Ah, nope, it should be has.

Zylann | 2016-09-16 20:59

Right, meant to say that.

Maverik | 2016-09-16 21:27

That dictionary merger works like a dream.

Darc | 2022-01-01 23:48

Since it is so good.
Gonna go push a ticket requesting to have this added to the Godot main repo.

Darc | 2022-01-02 00:06

:bust_in_silhouette: Reply From: sg7

There is no Update() method. The function for merging dictionaries has to be written.
When merging , the question which should be answered is:
“What to do if the destination dictionary already has a key which exists in the source?”

Typically, we would override the destination existing value unless the key points to the sub-dictionaries in both dictionaries. In such case we can merge the sub-dictionaries.

Testing dictionaries and the results :

var dest = {1:"a", 2:"b", 7:"e" }     
var source = {7:{5:"e", 6:"f"}, 4:{4:"d",8:[1,2,3]}}
#  result:
# (1:a), (2:b), (4:(4:d), (8:[1, 2, 3])), (7:(5:e), (6:f))

var dest1 = {1:"a", 2:"b", 7:{5:"e", 6:"f"} }
var source1 = {7:"c", 4:"d"}
#  result:
#  merge_dict = (1:a), (2:b), (4:d), (7:c)

var dest2 = {1:"a", 2:"b", 7:{5:"e", 6:"f"} }
var source2 = {7:{66:"c", 77:"g"}, 4:"d"}
#  result:
# (1:a), (2:b), (4:d), (7:(5:e), (6:f), (66:c), (77:g))

var dest3 = {1:"a", 2:"b", 3:{8:{12:"33", 10:"55"}, 9:"44"}}
var source3 = {4:"d", 3:{11:"abc",14:"abcd"}, 10:"67"}
# result
# (1:a), (10:67), (2:b), (3:(11:abc), (14:abcd), (8:(10:55), (12:33)), (9:44)), (4:d)

static func merge_dict(dest, source):
	for key in source:                     # go via all keys in source
		if dest.has(key):                  # we found matching key in dest
			var dest_value = dest[key]     # get value 
			var source_value = source[key] # get value in the source dict 			
			if typeof(dest_value) == TYPE_DICTIONARY:       
				if typeof(source_value) == TYPE_DICTIONARY: 
					merge_dict(dest_value, source_value)  
				else:
					dest[key] = source_value # override the dest value
			else:
				dest[key] = source_value     # add to dictionary 
		else:
			dest[key] = source[key]          # just add value to the dest

Test

func _ready():
	
	merge_dict(dest, source)
	print(dest)
	
	merge_dict(dest1, source1)
	print(dest1)
	
	merge_dict(dest2, source2)
	print(dest2)
	
	merge_dict(dest3, source3)
	print(dest3)
:bust_in_silhouette: Reply From: Merlin1846

Just like many other scripting languages

var PlayerData = {}
PlayerData["HELLO"] = "hi"
print(PlayerData)

{
“HELLO”:“hi”
}

See its quiet simple.

:bust_in_silhouette: Reply From: byrro

Here are two functions for merging Dictionaries and Arrays. They support both shallow and deep merging.

Please observe that, when using deep_merge=true in merge_array, sub-dictionaries and sub-arrays must be JSON serializable.

Usage examples, unit tests, and more on this Github gist.

Merge Arrays


func merge_array(array_1: Array, array_2: Array, deep_merge: bool = false) -> Array:
    var new_array = array_1.duplicate(true)
    var compare_array = new_array
    var item_exists

```
if deep_merge:
    compare_array = []
    for item in new_array:
        if item is Dictionary or item is Array:
            compare_array.append(JSON.print(item))
        else:
            compare_array.append(item)

for item in array_2:
    item_exists = item
    if item is Dictionary or item is Array:
        item = item.duplicate(true)
        if deep_merge:
            item_exists = JSON.print(item)

    if not item_exists in compare_array:
        new_array.append(item)
return new_array
```

Merge dictionaries


func merge_dict(dict_1: Dictionary, dict_2: Dictionary, deep_merge: bool = false) -> Dictionary:
    var new_dict = dict_1.duplicate(true)
    for key in dict_2:
        if key in new_dict:
            if deep_merge and dict_1[key] is Dictionary and dict_2[key] is Dictionary:
                new_dict[key] = merge_dict(dict_1[key], dict_2[key])
            elif deep_merge and dict_1[key] is Array and dict_2[key] is Array:
                new_dict[key] = merge_array(dict_1[key], dict_2[key])
            else:
                new_dict[key] = dict_2[key]
        else:
            new_dict[key] = dict_2[key]
    return new_dict

This code is licensed under BSD 3-Clause License | Copyright 2022 Hackverse.org