--- title: when two macros are faster than one draft: "false" --- While working on my Database datapack (still WIP), I knew I'd want to find # scenario ## dataset The data is stored in a storage `#_macro.array`. Array is populated with a total of 500 entries, each having `id` and `string` fields. ```json [ { id: 1, string: "entry1" }, ... { id: 500, string: "entry500" } ] ``` ## constraints The objective is to create an interface that receives a keyword, say `entry500`, and searches `#_macro.array` for an entry where the value of `string` matches the keyword. The keyword must be able to be entered by a player at runtime, and `#_macro.array` can have an arbitrary number of custom entries created by a player. In TypeScript, it would look something like this: ```ts function searchArray(keyword: string) { // logic return theRelevantEntry } searchArray('entry500') ``` In mcfunction, this is not so straightforward. Macros would make this really clean: ```vb function test_namespace:search_array {keyword: "entry500"} ``` Unfortunately, macros come with a performance hit. A more performant method, albeit less elegant, is to store the keyword in NBT storage prior to calling the function. The storage can be removed after the function is run: ```vb data modify storage test_namespace:test_namespace temp.keyword set value 'entry500' function test_namespace:search_array data remove storage test_namespace:test_namespace temp.keyword ``` Once the entry is found, it is stored in the `temp.result` storage, which can then be consumed by another function. Now for the logic to do the actual array searching... # one macro Macros allow us to reach into our array and pick out an entry that matching value in the `string` property. This is something that I didn't realize (for some reason) and was pointed out by **PuckiSilver** and **amandin** on the Datapack Hub discord server. ```vb ... one_macro.array[string:$(keyword)] ``` This method is super clean and results in a one liner that is wordy but simple: ```vb '# one_macro/_searcharray.mcfunction $data modify storage test_namespace:test_namespace temp.result set from storage test_namespace:test_namespace one_macro.array[string:$(keyword)] ``` `_searcharray` can then be called using the `temp.keyword` storage: ```vb '# one_macro/run.mcfunction data modify storage test_namespace:test_namespace temp.keyword set value 'entry500' function test_namespace:one_macro/_searcharray with storage test_namespace:test_namespace temp data remove storage test_namespace:test_namespace temp.keyword '# call the function that consumes 'temp.result', then remove it data remove storage test_namespace:test_namespace temp.result ``` # two macro Another way to crack the problem is through indexing. This was my original plan when I didn't realize that `...[string:$(keyword)]` was possible. This method requires the creation of an index of the field that is going to be searched. The index will look something like this: ```json [ {entry1: 0}, {entry2: 1}, ... {entry500: 499} ] ``` The *key*, e.g. `entry2:` corresponds with the value of a `string` field in the main array, while the value `1` indicates the main array index where we'll find the full entry. The index can be searched with a direct path, `index.$(keyword)`, and the main array can also be searched with a direct reference to the entry index, `array.#(index)`. Keep in mind that *the index must already exist prior to running the search function*. In a practical application, an index could be updated every time the main array is updated. A scheduled task could also audit the index to ensure that it's up to date. The index search looks like this: ```vb '# two_macro/_searchindex.mcfunction $data modify storage test_namespace:test_namespace temp.index set from storage test_namespace:test_namespace two_macro.index.$(keyword) ``` And the array search looks like this: ```vb '# two_macro/_searcharray.mcfunction $data modify storage test_namespace:test_namespace temp.result set from storage test_namespace:test_namespace two_macro.array[$(index)] ``` The index and array search functions are then called using the `temp.keyword` storage: ```vb '# two_macro/run.mcfunction data modify storage test_namespace:test_namespace temp.keyword set value 'entry500' function test_namespace:two_macro/_searchindex with storage test_namespace:test_namespace temp function test_namespace:two_macro/_searcharray with storage test_namespace:test_namespace temp data remove storage test_namespace:test_namespace temp.keyword data remove storage test_namespace:test_namespace temp.index '# call the function that consumes 'temp.result', then remove it data remove storage test_namespace:test_namespace temp.result ```