mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-25 15:14:35 +00:00
137 lines
2.6 KiB
Lua
137 lines
2.6 KiB
Lua
--[[
|
|
sequence - functional + oo wrapper for ordered tables
|
|
|
|
mainly beneficial when used for method chaining
|
|
to save on typing and data plumbing
|
|
]]
|
|
|
|
local path = (...):gsub("sequence", "")
|
|
local table = require(path .. "tablex") --shadow global table module
|
|
local functional = require(path .. "functional")
|
|
local stable_sort = require(path .. "sort").stable_sort
|
|
|
|
--(not a class, because we want to be able to upgrade tables that are passed in without a copy)
|
|
local sequence = {}
|
|
sequence.__index = sequence
|
|
setmetatable(sequence, {
|
|
__index = table,
|
|
__call = function(self, ...)
|
|
return sequence:new(...)
|
|
end,
|
|
})
|
|
|
|
--iterators as method calls
|
|
--(no pairs, sequences are ordered)
|
|
--todo: pico8 like `all`
|
|
sequence.ipairs = ipairs
|
|
sequence.iterate = ipairs
|
|
|
|
--upgrade a table into a sequence, or create a new sequence
|
|
function sequence:new(t)
|
|
return setmetatable(t or {}, sequence)
|
|
end
|
|
|
|
--sorting default to stable
|
|
sequence.sort = stable_sort
|
|
|
|
--patch various interfaces in a type-preserving way, for method chaining
|
|
|
|
--import copying tablex
|
|
--(common case where something returns another sequence for chaining)
|
|
for _, v in ipairs({
|
|
"keys",
|
|
"values",
|
|
"dedupe",
|
|
"collapse",
|
|
"append",
|
|
"shallow_overlay",
|
|
"deep_overlay",
|
|
"copy",
|
|
"shallow_copy",
|
|
"deep_copy",
|
|
}) do
|
|
local table_f = table[v]
|
|
sequence[v] = function(self, ...)
|
|
return sequence(table_f(self, ...))
|
|
end
|
|
end
|
|
|
|
--aliases
|
|
for _, v in ipairs({
|
|
{"flatten", "collapse"},
|
|
}) do
|
|
sequence[v[1]] = sequence[v[2]]
|
|
end
|
|
|
|
--import functional interface in method form
|
|
|
|
--(common case where something returns another sequence for chaining)
|
|
for _, v in ipairs({
|
|
"map",
|
|
"map_field",
|
|
"map_call",
|
|
"filter",
|
|
"remove_if",
|
|
"zip",
|
|
"combine",
|
|
"stitch",
|
|
"map_stitch",
|
|
"cycle",
|
|
"map_cycle",
|
|
"chain",
|
|
"map_chain",
|
|
}) do
|
|
local functional_f = functional[v]
|
|
sequence[v] = function(self, ...)
|
|
return sequence(functional_f(self, ...))
|
|
end
|
|
end
|
|
|
|
--(cases where we don't want to construct a new sequence)
|
|
for _, v in ipairs({
|
|
"map_inplace",
|
|
"filter_inplace",
|
|
"foreach",
|
|
"reduce",
|
|
"any",
|
|
"none",
|
|
"all",
|
|
"count",
|
|
"contains",
|
|
"sum",
|
|
"mean",
|
|
"minmax",
|
|
"max",
|
|
"min",
|
|
"find_min",
|
|
"find_max",
|
|
"find_nearest",
|
|
"find_match",
|
|
}) do
|
|
sequence[v] = functional[v]
|
|
end
|
|
|
|
|
|
--aliases
|
|
for _, v in ipairs({
|
|
{"remap", "map_inplace"},
|
|
{"map_stitch", "stitch"},
|
|
{"map_cycle", "cycle"},
|
|
{"find_best", "find_max"},
|
|
}) do
|
|
sequence[v[1]] = sequence[v[2]]
|
|
end
|
|
|
|
--(anything that needs bespoke wrapping)
|
|
function sequence:partition(f)
|
|
local a, b = functional.partition(self, f)
|
|
return sequence(a), sequence(b)
|
|
end
|
|
|
|
function sequence:unzip(f)
|
|
local a, b = functional.unzip(self, f)
|
|
return sequence(a), sequence(b)
|
|
end
|
|
|
|
return sequence
|