-
Notifications
You must be signed in to change notification settings - Fork 30
/
sequence.lua
136 lines (119 loc) · 2.63 KB
/
sequence.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
--[[
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