Created
June 28, 2019 08:40
-
-
Save MarcoLizza/82ae973674ea6faf19deff4aa434722d to your computer and use it in GitHub Desktop.
Functional approach to LUA tables.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Copyright (c) 2018-2019 by Marco Lizza (marco.lizza@gmail.com) | |
This software is provided 'as-is', without any express or implied | |
warranty. In no event will the authors be held liable for any damages | |
arising from the use of this software. | |
Permission is granted to anyone to use this software for any purpose, | |
including commercial applications, and to alter it and redistribute it | |
freely, subject to the following restrictions: | |
1. The origin of this software must not be misrepresented; you must not | |
claim that you wrote the original software. If you use this software | |
in a product, an acknowledgement in the product documentation would be | |
appreciated but is not required. | |
2. Altered source versions must be plainly marked as such, and must not be | |
misrepresented as being the original software. | |
3. This notice may not be removed or altered from any source distribution. | |
]] -- | |
local function map(array, callback) -- mapper(value, index, length, array) | |
local result = {} | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
result[index] = callback(value, index, length, array) | |
end | |
return result | |
end | |
local function filter(array, callback) -- filter(value, index, length, array) | |
local result = {} | |
local length = #array | |
local n = 0 | |
for index = 1, length do | |
local value = array[index] | |
if callback(value, index, length, array) then | |
n = n + 1 | |
result[n] = value | |
end | |
end | |
return result | |
end | |
local function reduce(array, callback, initial_value) -- reducer(accumulator, value, index, length, array) | |
local accumulator = initial_value | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
if accumulator == nil then | |
accumulator = value | |
else | |
accumulator = callback(accumulator, value, index, length, array) | |
end | |
end | |
return accumulator | |
end | |
local function for_each(array, callback) -- callback(value, index, length, array) | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
callback(value, index, length, array) | |
end | |
end | |
local function every(array, callback) -- callback(value, index, length, array) | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
if not callback(value, index, length, array) then | |
return false, index | |
end | |
end | |
return true, nil | |
end | |
local function some(array, callback) -- callback(value, index, length, array) | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
if callback(value, index, length, array) then | |
return true, index | |
end | |
end | |
return false, nil | |
end | |
local function find(array, callback) -- callback(value, index, length, array) | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
if callback(value, index, length, array) then | |
return value, index | |
end | |
end | |
return nil, nil | |
end | |
local function erase_if(array, callback) -- callback(value, index, length, array) | |
local erased = 0 | |
local length = #array | |
for index = length, 1, -1 do | |
local value = array[index] | |
local erase, stop = callback(value, index, length, array) | |
if erase then | |
table.remove(array, index) | |
erased = erased + 1 | |
end | |
if stop then | |
break | |
end | |
end | |
return erased | |
end | |
local function displace(array, callback) -- shuffle (?), rotate, reverse | |
local result = {} | |
local length = #array | |
for index = 1, length do | |
local value = array[index] | |
result[callback(value, index, length, array)] = value | |
end | |
return result | |
end | |
local function generate(callback) | |
local result = {} | |
local index = 1 | |
while true do | |
local value = callback(index) | |
if value == nil then | |
break | |
end | |
result[index] = value | |
index = index + 1 | |
end | |
return result | |
end | |
local function index_of(array, search, from) | |
local length = #array | |
for index = from or 1, length do | |
local value = array[index] | |
if value == search then | |
return index | |
end | |
end | |
return 0 | |
end | |
local function reversed(array) | |
local result = {} | |
local length = #array | |
for index = 1, length do | |
result[length - index + 1] = array[index] | |
end | |
return result | |
end | |
local function reverse(array) | |
local length = #array | |
for index = 1, math.floor(length / 2) do | |
array[length - index + 1], array[index] = array[index], array[length - index + 1] | |
end | |
end | |
local function rotated(array, amount) | |
local result = {} | |
local length = #array | |
amount = amount % length | |
-- Don't bail out for zero amount, since we need to copy the array! | |
if amount < 0 then -- fix the amount if negative | |
amount = amount + length | |
end | |
for index = 1, length do | |
local value = array[index] | |
local j = index + amount | |
if j > length then | |
j = j - length | |
end | |
result[j] = value | |
end | |
return result | |
end | |
local function rotate(array, amount) | |
local length = #array | |
amount = amount % length | |
if amount == 0 then | |
return | |
end | |
if amount < 0 then -- fix the amount if negative | |
amount = amount + length | |
end | |
-- compute the least-common-multiple | |
local a = length | |
local lcm = amount | |
local b = a % lcm | |
while b ~= 0 do | |
a = lcm | |
lcm = b | |
b = a % lcm | |
end | |
for i = 1, lcm do | |
local aux = array[i] | |
local j = i + amount | |
while j ~= i do | |
array[j], aux = aux, array[j] | |
j = j + amount | |
if j > length then | |
j = j - length | |
end | |
end | |
array[i] = aux | |
end | |
end | |
local function shuffled(array) -- inside-out algorithm | |
local result = {} | |
for i = 1, #array do | |
local j = math.random(i) | |
if i ~= j then | |
result[i] = result[j] | |
end | |
result[j] = array[i] | |
end | |
return result | |
end | |
local function shuffle(array) | |
for i = #array, 2, -1 do | |
local j = math.random(i) | |
array[j], array[i] = array[i], array[j] | |
end | |
end | |
local function unique(array) | |
-- TODO: implement a duplicate removal. | |
return array | |
end | |
local function new(length, value) | |
local result = {} | |
for index = 1, length do | |
result[index] = value or index - 1 | |
end | |
return result | |
end | |
local function equals(a, b) | |
if a == b then | |
return true | |
end | |
if not a or not b then | |
return false | |
end | |
if #a ~= #b then | |
return false | |
end | |
for index = 1, #a do | |
if a[index] ~= b[index] then | |
return false | |
end | |
end | |
return true | |
end | |
local function copy(array, from, to) | |
local result = {} | |
local n = 0 | |
for index = from or 1, to or #array do | |
n = n + 1 | |
result[n] = array[index] | |
end | |
return result | |
end | |
local function merge(a, b) | |
local n = #a | |
for index = 1, #b do | |
n = n + 1 | |
a[n] = b[index] | |
end | |
end | |
local function merged(a, b) | |
local result = {} | |
local n = 0 | |
for index = 1, #a do | |
n = n + 1 | |
a[n] = a[index] | |
end | |
for index = 1, #b do | |
n = n + 1 | |
a[n] = b[index] | |
end | |
return result | |
end | |
return { | |
map = map, | |
filter = filter, | |
reduce = reduce, | |
for_each = for_each, | |
every = every, | |
some = some, | |
find = find, | |
erase_if = erase_if, | |
displace = displace, | |
generate = generate, | |
index_of = index_of, | |
reversed = reversed, | |
reverse = reverse, | |
rotated = rotated, | |
rotate = rotate, | |
shuffled = shuffled, | |
shuffle = shuffle, | |
unique = unique, | |
new = new, | |
equals = equals, | |
copy = copy, | |
merge = merge, | |
merged = merged | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment