Module:PrefixedIter

Jump to navigation Jump to search
Documentation[create] [refresh]
This module has no documentation. If you know how to use this module, please create it.
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