summaryrefslogtreecommitdiff
path: root/czzc/table.lua
blob: 92619ebbc6013662a1de0a81bf098637ce062c59 (plain)
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
local M = {}

-- shallow copies a table, dst optional.
M.copy = function(src, dst)
    dst = dst or {}
    for k, v in pairs(src) do
        dst[k] = v
    end
    return dst
end

-- recursively copies a table, dst optional.
-- might implode for infinitely nested tables.
M.deepcopy = function(src, dst)
    dst = dst or {}
    -- convenience.
    if type(src) ~= "table" then return src end
    for k, v in pairs(src) do
        dst[k] = M.deepcopy(v)
    end
    return dst
end

-- replaces all values of a table with fn(value).
M.map = function(fn, tbl)
    local res = {}
    for k, v in pairs(tbl) do
        res[k] = fn(v)
    end
    return res
end

-- in-place version of the above.
M.map_ip = function(fn, tbl)
    for k, v in pairs(tbl) do
        tbl[k] = fn(v)
    end
    return tbl -- redundant, technically, but i thought i'd include it anyway.
end

-- discards or keeps values from a table based on a predicate.
-- this one only supports arrays, not maps.
M.filter = function(pred, arr)
    local res = {}
    for i, v in ipairs(arr) do
        if pred(v) then
            table.insert(res, v)
        end
    end
    return res
end

M.filter_ip = function(pred, arr) -- in-place.
    for i = #arr, 1, -1 do -- we need to iterate backwards here to prevent the.
        if not pred(arr[i]) then
            table.remove(arr, i)
        end
    end
    return arr
end

-- like filter, but works on map-style tables instead.
M.filter_map = function(pred, map)
    local res = {}
    for k, v in pairs(map) do
        if pred(v) then
            res[k] = v
        end
    end
    return res
end

M.filter_map_ip = function(pred, map) -- in-place.
    for k, v in pairs(map) do
        if not pred(v) then
            map[k] = nil
        end
    end
    return map
end

-- "folds" an operation over an array. i.e foldr(*, e, {a, b, c, d}) = a * (b * (c * (d * e))).
M.foldr = function(op, startval, arr) 
    local res = startval or 0 -- sensible default?
    for i = #arr, 1, -1 do
        res = op(res, arr[i])
    end
    return res
end

-- same as above, but the other way i.e ((e * a) * b) * c
M.foldl = function(op, startval, arr)
    local res = startval or 0 
    for i=1, #arr do
        res = op(res, arr[i])
    end
    return res
end

M.sum = function(arr)
    return M.foldl(function(a,b) return a+b end, 0, arr)
end

M.product = function(arr)
    return M.foldl(function(a,b) return a*b end, 0, arr)
end

return M