[Open Source] Table Manipulation Utility

https://www.roblox.com/library/5136940156/Table-Manipulation-Utility

The Premise

In an effort to shorten code and explore a unique paradigm of coding, I created a library that, with the help of some obscure and, on its surface, unorthodox metamethods, allows for more intuitive manipulation of tables (wow that was wordy). In other words, this library emulates most of the Lua table methods with metamethod operations. As a quick side note, many of you may initially view this unique style of code as alien or completely unconventional. Although it is quite strange, and probably isn’t for those who prefer OOP utilities, it does reduce the verbosity and improve the overall quality of your code – maybe not in terms of speed and optimization, as these processes do incur slightly more overhead than an OOP approach would, but in the general lexical flow of code.

This utility library takes advantage of operations like the invocation (calling something) and a handful of mathematical operations. I tried my best to give each table operation the most fitting metamethod operation, though squeezing in as many useful functions as I could got to be pretty difficult, so my apologies if the amount of method overloading is to much for you all. A complete reference guide can be found below.

Usage

API Reference

Special cases

Negative index
In every operation that involves providing an index value, a negative integer will represent the index position offset from the end of an ordinal table, going right to left. In other words, if i < 0 then the true index is #table + i + 1 (i must be nonzero as well).

Chaining
For all invocation operations, the table being invoked will be returned (except when the table has being cloned). Hence, an assignment statement is usually unnecessary as everything can be written in one expression. Additionally, negation (-), modulus (%), and exponentiation (^) will return different tables with the same custom metamethods attached to them. All returned table(s) will include such metadata, with the exception of util() (see below).

Initialization

Simply require the the module and call the associated function like so:

table util () – Returns a blank table with the appropriate metamethods
table util (table tab) – Returns tab with the appropriate metamethods attached
table util (table tab, bool removeMeta) – If true, removeMeta will remove all of tab’s metadata
table util (int count, Variant value) – Initializes a table of values, where the amount is specified by count, and attaches appropriate metamethods (equivalent to table.create)

Duplication

table tab() – Returns a shallow copy
table tab{} – Returns a deep copy

original = util {1, {}, 3}
shallow = original()
deep = original {}

print (original[2] == shallow[2]) --> true
print (original[2] == deep[2]) --> false

Concatenation

string table .. (string sep) – Converts ordinal elements of a table into a string separated by sep (equivalent to table.concat)

print (util {1, 2, 3} .. ', ') --> '1, 2, 3'

Insertion

self table (Variant value) – Inserts a non-nil value at index #table + 1 (equivalent to table.insert)
self table (Variant value, int index) – Inserts a non-nil value at index (also equivalent to table.insert)

tab = util {1, 2, 3}
tab (0, 1) --Inserts at beginning
tab (4) --Inserts at end
print (tab .. ', ') --> '0, 1, 2, 3, 4'

Deletion

self table (nil) – Removes the value at index #table + 1 (equivalent to table.remove)
self table (nil, int index) – Removes the value at index (also equivalent to table.remove)

tab = util {1, 2, 3}
tab (nil) --Deletes element at end
tab (nil, 1) --Deletes first element
print (tab .. ', ') --> '2'

Batch Operations

self table (Variant value, table indices, bool shift) – Takes a table of indices and either directly assigns them if shift is true or inserts them into the table if shift is false or left omitted
self table (nil, table indices, bool shift) – Takes a table of indices and either assigns the corresponding indices to nil if shift is true or removes them if shift if false or left omitted

tab = util ()
tab (true, {'Frame', 'ScrollingFrame'})
tab (nil, {'Frame'})

NOTE #1 - Non-numeric elements indices will always be directly assigned to value in both insertion and deletion operations regardless shift
NOTE #2 - Be careful not to accidentally insert a single table instead of inserting the elements themselves; you must supply at least 3 arguments for a batch operation to occur.

self table (table t1, int start, int stop, int index, bool shift) – Takes table t1, cropped by start and stop, and either appends it to the table if shift is true or replaces it into the table being invoked (equivalent to table.move) if shift is false or left omitted. int index defaults to 1.

tab1 = util {1, 4}
tab2 = util {2, 3}
tab1 (tab2, 1, 2, 2, true) --> {1, 2, 3, 4}

self table (table elements) – Assigns the corresponding key, value pairs within elements to the table being invoked (does not shift ordinal elements)

tokens = util {}
tokens {
   Player1 = 5,
   Player2 = 2,
   Player3 = 10
}

table tab ^ {int start, int stop} – Returns a range of values from tab (similar to table.move)

tab = util {5, 6, 7, 8}
range1 = tab ^ {2, -1} --> {6, 7, 8}
range2 = tab ^ {3} --> {7, 8}

Searches

table tab % {Variant value, bool global} – Performs a sequential search and returns a table of index matches (if none were found, the table will be empty). If global is true, the search will record all occurrences – otherwise it will exit after its first match.

Deferred: Multiplication & Division for unions & negations

Primitive retrieval

Variant table + int index – Indices int index in table
Variant table - int index – Indices int index from the end of the table

tab = util {1, 3, 4}
print(util + 2) --> 3
print(util - 1) --> 4
print(util + -1) --> 4

Miscellaneous

table -tab --Returns a reversed copy of tab (does not affect dictionary elements)

First, a table on which you’d like to perform operations must have the metamethods applied to it. Then, to insert, set, and remove values from a table, as well as copying the table its self, call the table as if it were a regular function.

clone = tab() --clones the table when the arguments are left void
tab (1) --Adds the value 1 to the end of the table (but does not clone it)
tab (1, 2) --Inserts the value one at index 2
tab {1, 2, 3} --Replaces tab elements with the corresponding table argument elements
tab(nil) --Removes the last element
tab(nil, 1) -- Removes the first element

As you can see, when a combination of arguments are passed through an invocation, a different operation is performed on the original table. As a nifty little side effect, the original table is returned after calling it and multiple methods can be chained together in one very long (or concise) expression.

clone = tab() {1, 2, 3} (nil, 2) --> {1, 3}
print(clone == tab) --> false

One thing I’d like to mention is that chaining like this can raise the ambiguity of your code. That is, you may misinterpret code or accidentally perform the wrong operation on the wrong object more often. I recommend that you provide comments for such statements if you want to completely switch to this sort of thing.

The utility also taken advantage of some of the mathematical metamethods that are almost never integrated into tables.

t1, t2 = util {1, 2, 3, 4}, util {1, 3, 1}

--Comparing/contrasting two tables [DEFERRED]
same = t1 * t2 --> N/A
diff = t1 / t2 --> N/A

--Capturing & indexing a range of ordinal elements
tableRange = t1 ^ {2, 4} --> {2, 3, 4}
last = t1 - 1 --> 4
first = t1 + 1 --> 1

--Searching a table for value(s) (returns table of indices)
--Second parameter specifies whether or not a global search is performed
t2 % {1, true} --> {1, 3} 
t2 % {1, false} --> {1}
t1 % {5} --> {}

--Miscellaneous
print(t1 .. ' ') --> '1 2 3 4'
print(t1 .. ', ') --> '1, 2, 3, 4'
t1 (nil, t2 ^ {1, 3, true}) -- Deletes all elements equal to three

Negation (-), Modulus (%), exponentiation (^), subtraction (-), and addition (+) are the five mathematical symbols that offer some sort of functionality. Bear in mind that order of operations still applies, so be mindful of where you place everything

Moving Forward

Like I said previously, the style that I’m employing for this library will feel strange at first. But as you integrate more of this into your code, I guarantee that you’ll come to appreciate at least some aspect of it. If you all feel that the symbols I have used, as well as ones I haven’t, deserve different functions, by all means let me know. The project is open source and uploaded to GitHub, so don’t hesitate to contribute if something seems amiss. Thanks for staying with me all the way through!

6 Likes

Thanks for the great asset :smiley:

1 Like

Hi,

I am trying to find find a value in a table but always returns true

local TableCare = require(game:GetService(“ReplicatedStorage”).TableConstructs)

local test = TableCare()
– Insert Value at end
test(“666”)
– Inter at start
test(“555”, 1)
local findintable = test % {“55”, false}
if findintable(0) == nil then
print(“not found”)
end