mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-26 15:44:35 +00:00
[added] set module with full (-ish?) suite of set operations and efficient (non-linear) membership testing
closes #4
This commit is contained in:
parent
28e06c4a10
commit
e5be0df492
27
init.lua
27
init.lua
@ -1,22 +1,7 @@
|
|||||||
--[[
|
--[[
|
||||||
batteries for lua
|
batteries for lua
|
||||||
|
|
||||||
if required as the "entire library" (ie by this file), puts everything into
|
a collection of helpful code to get your project off the ground faster
|
||||||
global namespace by default as it'll presumably be commonly used
|
|
||||||
|
|
||||||
if not, several of the modules work as normal lua modules and return a table
|
|
||||||
for local-friendly use
|
|
||||||
|
|
||||||
the others that modify some global table can be talked into behaving as normal
|
|
||||||
lua modules as well by setting appropriate globals prior to inclusion
|
|
||||||
|
|
||||||
you can avoid modifying any global namespace by setting
|
|
||||||
|
|
||||||
BATTERIES_NO_GLOBALS = true
|
|
||||||
|
|
||||||
before requiring, then everything can be accessed as eg
|
|
||||||
|
|
||||||
batteries.table.stable_sort
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local path = ...
|
local path = ...
|
||||||
@ -32,7 +17,9 @@ local _tablex = require_relative("tablex")
|
|||||||
local _stable_sort = require_relative("stable_sort")
|
local _stable_sort = require_relative("stable_sort")
|
||||||
|
|
||||||
local _functional = require_relative("functional")
|
local _functional = require_relative("functional")
|
||||||
|
|
||||||
local _sequence = require_relative("sequence")
|
local _sequence = require_relative("sequence")
|
||||||
|
local _set = require_relative("set")
|
||||||
|
|
||||||
local _stringx = require_relative("stringx")
|
local _stringx = require_relative("stringx")
|
||||||
|
|
||||||
@ -69,8 +56,9 @@ local _batteries = {
|
|||||||
sort = _stable_sort,
|
sort = _stable_sort,
|
||||||
--
|
--
|
||||||
functional = _functional,
|
functional = _functional,
|
||||||
--
|
--collections
|
||||||
sequence = _sequence,
|
sequence = _sequence,
|
||||||
|
set = _set,
|
||||||
--geom
|
--geom
|
||||||
vec2 = _vec2,
|
vec2 = _vec2,
|
||||||
vec3 = _vec3,
|
vec3 = _vec3,
|
||||||
@ -97,8 +85,9 @@ function _batteries:export(self)
|
|||||||
--functional module also available separate from table
|
--functional module also available separate from table
|
||||||
functional = _functional
|
functional = _functional
|
||||||
|
|
||||||
--export sequence
|
--export collections
|
||||||
sequence = _sequence
|
sequence = _sequence
|
||||||
|
set = _set
|
||||||
|
|
||||||
--overlay onto math
|
--overlay onto math
|
||||||
_tablex.overlay(math, _mathx)
|
_tablex.overlay(math, _mathx)
|
||||||
@ -111,7 +100,7 @@ function _batteries:export(self)
|
|||||||
vec3 = _vec3
|
vec3 = _vec3
|
||||||
intersect = _intersect
|
intersect = _intersect
|
||||||
|
|
||||||
--misc :)
|
--"misc" :)
|
||||||
unique_mapping = _unique_mapping
|
unique_mapping = _unique_mapping
|
||||||
state_machine = _state_machine
|
state_machine = _state_machine
|
||||||
async = _async
|
async = _async
|
||||||
|
138
set.lua
Normal file
138
set.lua
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
--[[
|
||||||
|
set type with appropriate operations
|
||||||
|
]]
|
||||||
|
|
||||||
|
local path = (...):gsub("set", "")
|
||||||
|
local class = require(path .. "class")
|
||||||
|
local table = require(path .. "tablex") --shadow global table module
|
||||||
|
|
||||||
|
local set = class()
|
||||||
|
|
||||||
|
--construct a new set
|
||||||
|
--elements is an optional ordered table of elements to be added to the set
|
||||||
|
function set:new(elements)
|
||||||
|
self = self:init({
|
||||||
|
_keyed = {},
|
||||||
|
_ordered = {},
|
||||||
|
})
|
||||||
|
if elements then
|
||||||
|
for _, v in ipairs(elements) do
|
||||||
|
self:add(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--check if an element is present in the set
|
||||||
|
function set:has(v)
|
||||||
|
return self._keyed[v] or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--add a value to the set, if it's not already present
|
||||||
|
function set:add(v)
|
||||||
|
if not self:has(v) then
|
||||||
|
self._keyed[v] = true
|
||||||
|
table.insert(self._ordered, v)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--remove a value from the set, if it's present
|
||||||
|
function set:remove(v)
|
||||||
|
if self:has(v) then
|
||||||
|
self._keyed[v] = nil
|
||||||
|
table.remove_value(self._ordered, v)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--iterate the values in the set, along with their index
|
||||||
|
--the index is useless but harmless, and adding a custom iterator seems
|
||||||
|
--like a really easy way to encourage people to use slower-than-optimal code
|
||||||
|
function set:ipairs()
|
||||||
|
return ipairs(self._ordered)
|
||||||
|
end
|
||||||
|
|
||||||
|
--get a copy of the values in the set, as a simple table
|
||||||
|
function set:values()
|
||||||
|
return table.copy(self._ordered)
|
||||||
|
end
|
||||||
|
|
||||||
|
--modifying operations
|
||||||
|
|
||||||
|
--add all the elements present in the other set
|
||||||
|
function set:add_set(other)
|
||||||
|
for i, v in other:ipairs() do
|
||||||
|
self:add(v)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--remove all the elements present in the other set
|
||||||
|
function set:subtract_set(other)
|
||||||
|
for i, v in other:ipairs() do
|
||||||
|
self:remove(v)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--new collection operations
|
||||||
|
|
||||||
|
--copy a set
|
||||||
|
function set:copy()
|
||||||
|
return set:new():add_set(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
--create a new set containing the complement of the other set contained in this one
|
||||||
|
--the elements present in this set but not present in the other set will remain in the result
|
||||||
|
function set:complement(other)
|
||||||
|
return self:copy():subtract_set(other)
|
||||||
|
end
|
||||||
|
|
||||||
|
--alias
|
||||||
|
set.difference = set.complement
|
||||||
|
|
||||||
|
--create a new set containing the union of this set with another
|
||||||
|
--an element present in either set will be present in the result
|
||||||
|
function set:union(other)
|
||||||
|
return self:copy():add_set(other)
|
||||||
|
end
|
||||||
|
|
||||||
|
--create a new set containing the intersection of this set with another
|
||||||
|
--only the elements present in both sets will remain in the result
|
||||||
|
function set:intersection(other)
|
||||||
|
local r = set:new()
|
||||||
|
for i, v in self:ipairs() do
|
||||||
|
if other:has(v) then
|
||||||
|
r:add(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
--create a new set containing the symmetric difference of this set with another
|
||||||
|
--only the elements not present in both sets will remain in the result
|
||||||
|
--similiar to a logical XOR operation
|
||||||
|
--
|
||||||
|
--equal to self:union(other):subtract_set(self:intersection(other))
|
||||||
|
-- but with much less wasted effort
|
||||||
|
function set:symmetric_difference(other)
|
||||||
|
local r = set:new()
|
||||||
|
for i, v in self:ipairs() do
|
||||||
|
if not other:has(v) then
|
||||||
|
r:add(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i, v in other:ipairs() do
|
||||||
|
if not self:has(v) then
|
||||||
|
r:add(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
--alias
|
||||||
|
set.xor = set.symmetric_difference
|
||||||
|
|
||||||
|
--
|
||||||
|
return set
|
Loading…
Reference in New Issue
Block a user