Module:PrefixedIter

local p = {}

--[[ Similar to ipairs, but iterates over string keys with a constant prefix and a variable integer suffix.

Parameters: • some_table (table): the table to iterate over • prefix (string): the key prefix to use when iterating • allow_numberless (boolean, optional): if truthy, allows reading the key without an integer suffix as if it had the suffix 1. WARNING: behavior is unspecified if: 1) allow_numberless is truthy;     2) a key without an integer suffix is mapped to a value; 3) a key with integer suffix 1 is also mapped to a value.    In such cases, there is no guarantee on which of the two values is used.

Example: ``` local t = { a1 = 1, a2 = 4, a3 = 9 }

for index, value in prefixed_ipairs(t, "a") do	print(index, value) end ```

This prints ``` 1	1 2	4 3	9 ```

With `allow_numberless = true`, the above example would also work identically for the following table: ``` local t = { a = 1, a2 = 4, a3 = 9 } ```

However, with the following table, the example may print either 1 or 2 in the first line, depending on how prefixed_ipairs is currently implemented: ``` local t = { a = 1, a1 = 2, -- Don't do this! a2 = 4, a3 = 9 } ``` ]] function p.prefixed_ipairs(some_table, prefix, allow_numberless) local i = 0 return function i = i + 1 local value = some_table[prefix .. tostring(i)] if i == 1 and allow_numberless and some_table[prefix] ~= nil then value = some_table[prefix] end if value ~= nil then return i, value end end end

--[[ An extension to p.prefixed_ipairs that also allows to grab fields with suffixes from a predefined list.

Parameters: • some_table (table): the table to iterate over • prefix (string): the key prefix to use when iterating • fields (sequence of strings): the sequence of extra "fields", none inherently mandatory, that would be    retrieved from `some_table` for each element • allow_numberless (boolean, optional): if truthy, allows reading the key without an integer suffix as if it had the suffix 1. Same as with prefixed_ipairs, having both a no-integer key and a key with integer 1 is unspecified behavior.

When used as an iterator, returns 3 values: the index of the structure, the "base" value (non-field, without any suffix), and a table where field names are mapped to their values.

This function stops iterating whenever the first "base" value is missing, even if there are associated fields.

This pattern often occurs in template arguments. Example: ``` local args = { test1 = "cat", test1min = "5", test1max = "15", test2 = "tiger", test2min = "60", test2max = "175" } local fields = {"min", "max"}

for i, base, fields in p.prefixed_struct_ipairs(t, "test", fields) do   print(base .. ': ' .. fields.min .. '–' .. fields.max) end ```

This prints: ``` cat: 5–15 tiger: 60–175 ``` ]] function p.prefixed_struct_ipairs(some_table, prefix, fields, allow_numberless) local i = 0 return function i = i + 1 local base_prefix = prefix .. tostring(i) local base_value = some_table[base_prefix] if i == 1 and allow_numberless and some_table[prefix] ~= nil then base_prefix = prefix base_value = some_table[prefix] end if base_value ~= nil then local i_fields = {} for _, field_name in ipairs(fields) do i_fields[field_name] = some_table[base_prefix .. field_name] end return i, base_value, i_fields end end end

return p