Merge pull request #69594 from Mickeon/doc-peeves-read-a-dictionary

Overhaul Dictionary Documentation
This commit is contained in:
Rémi Verschelde 2022-12-05 18:07:43 +01:00
commit 65cbcaeaa5
No known key found for this signature in database
GPG key ID: C3336907360768E1

View file

@ -4,9 +4,8 @@
Dictionary type.
</brief_description>
<description>
Dictionary type. Associative container, which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements. In other programming languages, this data structure is sometimes referred to as a hash map or associative array.
Dictionary type. Associative container, which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding new entries. In other programming languages, this data structure is sometimes referred to as a hash map or associative array.
You can define a dictionary by placing a comma-separated list of [code]key: value[/code] pairs in curly braces [code]{}[/code].
Erasing elements while iterating over them [b]is not supported[/b] and will result in undefined behavior.
[b]Note:[/b] Dictionaries are always passed by reference. To get a copy of a dictionary which can be modified independently of the original dictionary, use [method duplicate].
Creating a dictionary:
[codeblocks]
@ -40,10 +39,10 @@
};
[/csharp]
[/codeblocks]
You can access a dictionary's values by referencing the appropriate key. In the above example, [code]points_dict["White"][/code] will return [code]50[/code]. You can also write [code]points_dict.White[/code], which is equivalent. However, you'll have to use the bracket syntax if the key you're accessing the dictionary with isn't a fixed string (such as a number or variable).
You can access a dictionary's value by referencing its corresponding key. In the above example, [code]points_dict["White"][/code] will return [code]50[/code]. You can also write [code]points_dict.White[/code], which is equivalent. However, you'll have to use the bracket syntax if the key you're accessing the dictionary with isn't a fixed string (such as a number or variable).
[codeblocks]
[gdscript]
export(String, "White", "Yellow", "Orange") var my_color
@export(String, "White", "Yellow", "Orange") var my_color
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
func _ready():
# We can't use dot syntax here as `my_color` is a variable.
@ -69,7 +68,9 @@
Dictionaries can contain more complex data:
[codeblocks]
[gdscript]
my_dict = {"First Array": [1, 2, 3, 4]} # Assigns an Array to a String key.
var my_dict = {
"First Array": [1, 2, 3, 4] # Assigns an Array to a String key.
}
[/gdscript]
[csharp]
var myDict = new Godot.Collections.Dictionary
@ -91,7 +92,7 @@
{"Yellow", 75},
{"Orange", 100}
};
pointsDict["blue"] = 150; // Add "Blue" as a key and assign 150 as its value.
pointsDict["Blue"] = 150; // Add "Blue" as a key and assign 150 as its value.
[/csharp]
[/codeblocks]
Finally, dictionaries can contain different types of keys and values in the same dictionary:
@ -118,63 +119,23 @@
};
[/csharp]
[/codeblocks]
[b]Note:[/b] Unlike [Array]s, you can't compare dictionaries directly:
The keys of a dictionary can be iterated with the [code]for[/code] keyword:
[codeblocks]
[gdscript]
var array1 = [1, 2, 3]
var array2 = [1, 2, 3]
func compare_arrays():
print(array1 == array2) # Will print true.
var dict1 = {"a": 1, "b": 2, "c": 3}
var dict2 = {"a": 1, "b": 2, "c": 3}
func compare_dictionaries():
print(dict1 == dict2) # Will NOT print true.
var groceries = {"Orange": 20, "Apple": 2, "Banana": 4}
for fruit in groceries:
var amount = groceries[fruit]
[/gdscript]
[csharp]
// You have to use GD.Hash().
public Godot.Collections.Array array1 = new Godot.Collections.Array{1, 2, 3};
public Godot.Collections.Array array2 = new Godot.Collections.Array{1, 2, 3};
public void CompareArrays()
var groceries = new Godot.Collections.Dictionary{{"Orange", 20}, {"Apple", 2}, {"Banana", 4}};
foreach (var (fruit, amount) in groceries)
{
GD.Print(array1 == array2); // Will print FALSE!!
GD.Print(GD.Hash(array1) == GD.Hash(array2)); // Will print true.
}
public Godot.Collections.Dictionary dict1 = new Godot.Collections.Dictionary{{"a", 1}, {"b", 2}, {"c", 3}};
public Godot.Collections.Dictionary dict2 = new Godot.Collections.Dictionary{{"a", 1}, {"b", 2}, {"c", 3}};
public void CompareDictionaries()
{
GD.Print(dict1 == dict2); // Will NOT print true.
// `fruit` is the key, `amount` is the value.
}
[/csharp]
[/codeblocks]
You need to first calculate the dictionary's hash with [method hash] before you can compare them:
[codeblocks]
[gdscript]
var dict1 = {"a": 1, "b": 2, "c": 3}
var dict2 = {"a": 1, "b": 2, "c": 3}
func compare_dictionaries():
print(dict1.hash() == dict2.hash()) # Will print true.
[/gdscript]
[csharp]
// You have to use GD.Hash().
public Godot.Collections.Dictionary dict1 = new Godot.Collections.Dictionary{{"a", 1}, {"b", 2}, {"c", 3}};
public Godot.Collections.Dictionary dict2 = new Godot.Collections.Dictionary{{"a", 1}, {"b", 2}, {"c", 3}};
public void CompareDictionaries()
{
GD.Print(GD.Hash(dict1) == GD.Hash(dict2)); // Will print true.
}
[/csharp]
[/codeblocks]
[b]Note:[/b] When declaring a dictionary with [code]const[/code], the dictionary itself can still be mutated by defining the values of individual keys. Using [code]const[/code] will only prevent assigning the constant with another value after it was initialized.
[b]Note:[/b] Erasing elements while iterating over dictionaries is [b]not[/b] supported and will result in unpredictable behavior.
[b]Note:[/b] When declaring a dictionary with [code]const[/code], the dictionary becomes read-only. A read-only Dictionary's entries cannot be overriden at run-time. This does [i]not[/i] affect nested [Array] and [Dictionary] values.
</description>
<tutorials>
<link title="GDScript basics: Dictionary">$DOCS_URL/tutorials/scripting/gdscript/gdscript_basics.html#dictionary</link>
@ -192,7 +153,7 @@
<return type="Dictionary" />
<param index="0" name="from" type="Dictionary" />
<description>
Constructs a [Dictionary] as a copy of the given [Dictionary].
Returns the same array as [param from]. If you need a copy of the array, use [method duplicate].
</description>
</constructor>
</constructors>
@ -200,30 +161,30 @@
<method name="clear">
<return type="void" />
<description>
Clear the dictionary, removing all key/value pairs.
Clears the dictionary, removing all entries from it.
</description>
</method>
<method name="duplicate" qualifiers="const">
<return type="Dictionary" />
<param index="0" name="deep" type="bool" default="false" />
<description>
Creates a copy of the dictionary, and returns it. The [param deep] parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects.
Creates and returns a new copy of the dictionary. If [param deep] is [code]true[/code], inner [Dictionary] and [Array] keys and values are also copied, recursively.
</description>
</method>
<method name="erase">
<return type="bool" />
<param index="0" name="key" type="Variant" />
<description>
Erase a dictionary key/value pair by key. Returns [code]true[/code] if the given key was present in the dictionary, [code]false[/code] otherwise.
[b]Note:[/b] Don't erase elements while iterating over the dictionary. You can iterate over the [method keys] array instead.
Removes the dictionary entry by key, if it exists. Returns [code]true[/code] if the given [param key] existed in the dictionary, otherwise [code]false[/code].
[b]Note:[/b] Do not erase entries while iterating over the dictionary. You can iterate over the [method keys] array instead.
</description>
</method>
<method name="find_key" qualifiers="const">
<return type="Variant" />
<param index="0" name="value" type="Variant" />
<description>
Returns the first key whose associated value is equal to [param value], or [code]null[/code] if no such value is found.
[b]Note:[/b] [code]null[/code] is also a valid key. If you have it in your [Dictionary], the [method find_key] method can give misleading results.
Finds and returns the first key whose associated value is equal to [param value], or [code]null[/code] if it is not found.
[b]Note:[/b] [code]null[/code] is also a valid key. If inside the dictionary, [method find_key] may give misleading results.
</description>
</method>
<method name="get" qualifiers="const">
@ -231,72 +192,89 @@
<param index="0" name="key" type="Variant" />
<param index="1" name="default" type="Variant" default="null" />
<description>
Returns the current value for the specified key in the [Dictionary]. If the key does not exist, the method returns the value of the optional default argument, or [code]null[/code] if it is omitted.
Returns the corresponding value for the given [param key] in the dictionary. If the [param key] does not exist, returns [param default], or [code]null[/code] if the parameter is omitted.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
<param index="0" name="key" type="Variant" />
<description>
Returns [code]true[/code] if the dictionary has a given key.
[b]Note:[/b] This is equivalent to using the [code]in[/code] operator as follows:
Returns [code]true[/code] if the dictionary contains an entry with the given [param key].
[codeblocks]
[gdscript]
# Will evaluate to `true`.
if "godot" in {"godot": "engine"}:
pass
var my_dict = {
"Godot" : 4,
210 : null,
}
print(my_dict.has("Godot")) # Prints true
print(my_dict.has(210)) # Prints true
print(my_dict.has(4)) # Prints false
[/gdscript]
[csharp]
// You have to use Contains() here as an alternative to GDScript's `in` operator.
if (new Godot.Collections.Dictionary{{"godot", "engine"}}.Contains("godot"))
var myDict = new Godot.Collections.Dictionary
{
// I am executed.
}
{ "Godot", 4 },
{ 210, default },
};
GD.Print(myDict.Contains("Godot")); // Prints true
GD.Print(myDict.Contains(210)); // Prints true
GD.Print(myDict.Contains(4)); // Prints false
[/csharp]
[/codeblocks]
This method (like the [code]in[/code] operator) will evaluate to [code]true[/code] as long as the key exists, even if the associated value is [code]null[/code].
In GDScript, this is equivalent to the [code]in[/code] operator:
[codeblock]
if "Godot" in {"Godot": 4}:
print("The key is here!") # Will be printed.
[/codeblock]
[b]Note:[/b] This method returns [code]true[/code] as long as the [param key] exists, even if its corresponding value is [code]null[/code].
</description>
</method>
<method name="has_all" qualifiers="const">
<return type="bool" />
<param index="0" name="keys" type="Array" />
<description>
Returns [code]true[/code] if the dictionary has all the keys in the given array.
Returns [code]true[/code] if the dictionary contains all keys in the given [param keys] array.
[codeblock]
var data = {"width" : 10, "height" : 20}
data.has_all(["height", "width"]) # Returns true
[/codeblock]
</description>
</method>
<method name="hash" qualifiers="const">
<return type="int" />
<description>
Returns a hashed 32-bit integer value representing the dictionary contents. This can be used to compare dictionaries by value:
Returns a hashed 32-bit integer value representing the dictionary contents.
[codeblocks]
[gdscript]
var dict1 = {0: 10}
var dict2 = {0: 10}
# The line below prints `true`, whereas it would have printed `false` if both variables were compared directly.
print(dict1.hash() == dict2.hash())
var dict1 = {"A": 10, "B": 2}
var dict2 = {"A": 10, "B": 2}
print(dict1.hash() == dict2.hash()) # Prints true
[/gdscript]
[csharp]
var dict1 = new Godot.Collections.Dictionary{{0, 10}};
var dict2 = new Godot.Collections.Dictionary{{0, 10}};
// The line below prints `true`, whereas it would have printed `false` if both variables were compared directly.
// Dictionary has no Hash() method. Use GD.Hash() instead.
GD.Print(GD.Hash(dict1) == GD.Hash(dict2));
var dict1 = new Godot.Collections.Dictionary{{"A", 10}, {"B", 2}};
var dict2 = new Godot.Collections.Dictionary{{"A", 10}, {"B", 2}};
// Godot.Collections.Dictionary has no Hash() method. Use GD.Hash() instead.
GD.Print(GD.Hash(dict1) == GD.Hash(dict2)); // Prints true
[/csharp]
[/codeblocks]
[b]Note:[/b] Dictionaries with the same keys/values but in a different order will have a different hash.
[b]Note:[/b] Dictionaries with equal content will always produce identical hash values. However, the reverse is not true. Returning identical hash values does [i]not[/i] imply the dictionaries are equal, because different dictionaries can have identical hash values due to hash collisions.
[b]Note:[/b] Dictionaries with the same entries but in a different order will not have the same hash.
[b]Note:[/b] Dictionaries with equal hash values are [i]not[/i] guaranteed to be the same, because of hash collisions. On the countrary, dictionaries with different hash values are guaranteed to be different.
</description>
</method>
<method name="is_empty" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the dictionary is empty.
Returns [code]true[/code] if the dictionary is empty (its size is [code]0[/code]). See also [method size].
</description>
</method>
<method name="keys" qualifiers="const">
<return type="Array" />
<description>
Returns the list of keys in the [Dictionary].
Returns the list of keys in the dictionary.
</description>
</method>
<method name="merge">
@ -304,19 +282,19 @@
<param index="0" name="dictionary" type="Dictionary" />
<param index="1" name="overwrite" type="bool" default="false" />
<description>
Adds elements from [param dictionary] to this [Dictionary]. By default, duplicate keys will not be copied over, unless [param overwrite] is [code]true[/code].
Adds entries from [param dictionary] to this dictionary. By default, duplicate keys are not copied over, unless [param overwrite] is [code]true[/code].
</description>
</method>
<method name="size" qualifiers="const">
<return type="int" />
<description>
Returns the number of keys in the dictionary.
Returns the number of entries in the dictionary. Empty dictionaries ([code]{ }[/code]) always return [code]0[/code]. See also [method is_empty].
</description>
</method>
<method name="values" qualifiers="const">
<return type="Array" />
<description>
Returns the list of values in the [Dictionary].
Returns the list of values in this dictionary.
</description>
</method>
</methods>
@ -325,21 +303,22 @@
<return type="bool" />
<param index="0" name="right" type="Dictionary" />
<description>
Returns [code]true[/code] if the dictionaries differ, i.e. their key or value lists are different (including the order).
Returns [code]true[/code] if the two dictionaries do not contain the same keys and values.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Dictionary" />
<description>
Returns [code]true[/code] if both dictionaries have the same contents, i.e. their keys list and value list are equal.
Returns [code]true[/code] if the two dictionaries contain the same keys and values. The order of the entries does not matter.
[b]Note:[/b] In C#, by convention, this operator compares by [b]reference[/b]. If you need to compare by value, iterate over both dictionaries.
</description>
</operator>
<operator name="operator []">
<return type="Variant" />
<param index="0" name="key" type="Variant" />
<description>
Returns a value at the given [param key] or [code]null[/code] and error if the key does not exist. For safe access, use [method get] or [method has].
Returns the corresponding value for the given [param key] in the dictionary. If the entry does not exist, fails and returns [code]null[/code]. For safe access, use [method get] or [method has].
</description>
</operator>
</operators>