lλdash
Luvit.io utility-belt library for functional programming. Provides support for the usual functional suspects (each, map, reduce, filter...) without extending Lua core objects.
Install
npm install ludash
If you're not familiar with npm check this out:
- https://github.com/voronianski/luvit-npm-example#how-to
- https://github.com/luvitrocks/luvit-module-boilerplate#whats-npm
Example
local _ = require('ludash') local people = { { name = 'Robert', age = 24 }, { name = 'Simona', age = 29 }, { name = 'Jekyll', age = 26 }, { name = 'Aurora', age = 24 }} local function twentyFour (human) return human.age == 24end local results = _.chain(people):filter(twentyFour):sortBy('name'):value() p(results)-- will output new table:-- { {name = 'Aurora', age = 24}, {name = 'Robert', age = 24} }
Documentation
The list of functions available inside ludash can be classified into such categories:
Collection functions are mostly meant for Lua tables which contains both an array-part and/or a map-part. Array functions meant for array lists or sequences. Object functions are meant for instances/classes. Also ludash provides a bunch of helpful utility methods and chaining support.
The HTML version of this doc is available at http://luvitrocks.github.io/ludash.
Collection functions (Arrays or Objects)
each(table, iterator)
Alias: forEach
Iterates over a table of elements, yielding each in turn to an iterator function. Each invocation of iterator is called with three arguments: (element, index, list)
. If list is a Lua map-like object, iterator's arguments will be (value, key, list)
.
_.each({1, 2, 3}, print)-- => prints each number in turn:-- => 1 1-- => 2 2-- => 3 3 _.each({one=1, two=2, three=3}, function(num, key) print(num) end)-- => prints each number in turn:-- => one 1-- => two 2-- => three 3
Also attention is paid to performance, so pairs
, ipairs
and table.insert
are not used for lists providing higher execution speed. Based on Lua perf benchmarks.
map(table, iterator)
Alias: collect
Produces a new array of values by mapping each value in table through a transformation function (iterator). If list is a Lua map-like object, iterator's arguments will be (value, key, list)
.
_.map({1, 2, 3}, function (num) return num * 3 end)-- => {3, 6, 9}_.map({one=1, two=2, three=3}, function (num) return num * 3 end)-- => {3, 6, 9}
reduce(table, iterator)
Aliases: inject
, foldl
Boils down a list of values into a single table. Memo is the initial state of the reduction, and each successive step of it should be returned by iterator. The iterator is passed four arguments: the memo
, then the value
and index
(or key
) of the iteration, and finally a reference to the entire list
.
local sum = _.reduce({1, 2, 3}, function (memo, val) return memo val end, 0)-- => 6 local str = _.reduce({{x='a'}, {x='b'}, {x='c'}}, function (memo, val) return memo.x .. val.x end)-- => 'abc'
reduceRight(table, iterator)
Alias: foldr
Similar to _.reduce
, but performs from right to left.
local t = {{0, 1}, {2, 3}, {4, 5}}local flat = _.reduceRight(t, function (memo, val) return _.concat(memo, val) end, {})-- => {4, 5, 2, 3, 0, 1}
find(table, iterator)
Alias: detect
Looks through each value in the table, returning the first one that passes a truth test (iterator). The function returns as soon as it finds an acceptable element, and doesn't traverse the entire table.
_.find({1, 2, 3, 4, 5, 6}, function (num) return num % 2 == 0 end)-- => 2
filter(table, iterator)
Alias: select
Looks through each value in the table, returning an array of all the values that pass a truth test (iterator).
_.filter({1, 2, 3, 4, 5, 6}, function (num) return num % 2 == 0 end)-- => {2, 4, 6}
where(table, properties)
Looks through each value in the table, returning an array of all the values that contain all of the key-value pairs listed in properties.
_.where(listOfPlays, {author="Shakespeare", year=1611})-- => -- {-- {title="Cymbeline", author="Shakespeare", year=1611}, -- {title="The Tempest", author="Shakespeare", year=1611}-- }
every(table, predicate)
Alias: all
Checks whether or not all elements pass a validation test.
_.all({2,4,6}, function (num) return num %2 == 0 end)-- => true
contains(table, value)
Alias: include
Returns true
if the value is present in the table.
_.contains({6, 8, 10, 16}, 8) -- => true_.contains({a='foo', b='bar'}, 'bar') -- => true_.contains({nil, true, 0, true, true}, false) -- => false
some(table, predicate)
Alias: any
Returns true
if any of the values in the table pass the predicate truth test. Stops traversing the table if a true
element is found.
local function isUpper (value) return value:upper() == value end_.some({'a', 'B', 'c'}, isUpper) -- => true
size(...)
When given a table, provides the count for the very number of values in that table.
_.size({1, 2, 3}) -- => 3_.size({one=1, two=2}) -- => 2
When given a list of arguments, returns the count of these arguments.
_.size(1, 2, 3) -- => 3_.size('a', 'b', {}, function () end) -- => 4
sort(table, [comparator])
Sorts a table and relies on Lua's native table.sort
. Handles custom comparison functions.
_.sort({'b','a','d','c'}) -- => "{'a','b','c','d'}" _.sort({'b','a','d','c'}, function (a,b) return a:byte() > b:byte() end) -- => "{'d','c','b','a'}"
Array functions
flatten(array, [shallow])
Flattens a nested array (the nesting can be to any depth). If you pass shallow flag, the array will only be flattened a single level.
_.flatten({1,{2,3},{4,5,{6,7}}}) -- => {1,2,3,4,5,6,7}_.flatten({1,{2},{{3}}}, true) -- => {1,{2},{{3}}}
reverse(array)
Reverses an array table order.
_.reverse({1,2,3,4,5,6})-- => {6,5,4,3,2,1}
concat(...)
Creates a new array by concatenating the arguments passed in. It does not alter the original versions of the values passed in.
_.concat(1, 2, 3, 4, 5, 6)-- => {1,2,3,4,5,6}_.concat({1,2,3}, {4,5,6})-- => {1,2,3,4,5,6}
Object functions
keys(table)
Retrieve all the names of the tables's properties. The order of the keys is not guaranteed to be consistent.
_.keys({one=1, two=2, three=3})-- => {"one", "two", "three"}
values(table)
Retrieve all the values of the tables's properties. The order of the keys is not guaranteed to be consistent.
_.keys({one=1, two=2, three=3})-- => {1, 2, 3}
invert(table)
Alias: mirror
Returns a copy of the table where the keys have become the values and the values the keys.
_.invert({Moe="Moses", Larry="Louis", Curly="Jerome"})-- => {Moses="Moe", Louis="Larry", Jerome="Curly"} _.invert {'a','b','c'} -- => "{a=1, b=2, c=3}"
isEqual(table1, table2, [useMetaTable])
Alias: compare
Performs a deep comparison between the two objects, to determine if they should be considered equal. It can compare strings, functions, nil, booleans. Compares tables by reference or by values. If optional useMetaTable
boolean is passed (default false
), the equality operator ==
will be used if one of the given objects has a metatable implementing __eq
.
_.isEqual(1, 1) -- => true_.isEqual(true, false) -- => false_.isEqual(3.14, math.pi) -- => false_.isEqual({3,4,5}, {3,4,{5}}) -- => false
isEmpty(object)
Returns true
if object contains no values.
_.isEmpty('') -- => true_.isEmpty({}) -- => true_.isEmpty({1, 2, 3}) -- => false
isArray(object)
Returns true
if object is an Array (i.e. a sequence).
_.isArray({}) -- => true_.isArray({1, 2, 3}) -- => true_.isArray({'a', 'b', 'c'}) -- => true
isObject(object)
Alias: isTable
Returns true
if object is an actual Object (i.e a Table).
_.isTable({}) -- => true_.isTable(math) -- => true_.isTable(string) -- => true
isFunction(object)
Returns true
if object is a Function.
_.isFunction(print) -- => true_.isFunction(function () end) -- => true_.isFunction({}) -- => false
isString(object)
Returns true
if object is a String.
_.isString('') -- => true_.isString('Hello') -- => false_.isString({}) -- => false
isNumber(object)
Returns true
if object is a Number.
_.isNumber(math.pi) -- => true_.isNumber(math.huge) -- => true_.isNumber(0/0) -- => true_.isNumber() -- => false
isBoolean(object)
Returns true
if object is either true
or false
.
_.isBoolean(true) -- => true_.isBoolean(false) -- => true_.isBoolean(1 == 1) -- => true_.isBoolean(print) -- => false
toBoolean(object)
Converts any given object to a Boolean.
_.toBoolean(true) -- => true_.toBoolean(false) -- => false_.toBoolean(nil) -- => false_.toBoolean({}) -- => true_.toBoolean(1) -- => true
isNil(object)
Returns true
if the value of object is nil
.
_.isNil() -- => true_.isNil(nil) -- => true_.isNil({}) -- => false
Utility functions
identity(value)
Returns the same value that is used as the argument. In math: f(x) = x
. This function is used as default iterator inside ludash.
local moe = {name='moe'}_.identity(moe);-- => {name='moe'}
times(n, iterator)
Calls a given iterator function n
times.
local func = ('Luvit programming'):gmatch('.')_.times(5, func) -- => {'L','u','v','i','t'}
once(func)
Produces a function that runs only once. Successive calls to this function will still yield the same input.
local sq = _.once(function (v) return v * v end)sq(1) -- => 1sq(2) -- => 1sq(3) -- => 1
uniqueId([template])
Alias: uid
Generates and returns a globally-unique integer id for the current session. It can handle string templates for formatted output with Lua string.format
or callback function for the same purpose.
_.uniqueId('id%s') -- => 'id2' local function formatter (id) return '$'..id..'$' end_.uniqueId(formatter) -- => '$id1$'
functions(table, [recurseMetaTable])
Alias: methods
Returns a sorted array of the names of every method in a table. If recurseMetaTable
flag is provided (default false
) and if the given object has a metatable implementing an __index
field pointing to another table, will also recurse on this table.
_.functions(lu)-- => {"all", "any", "bind", "bindAll", "clone", "compact", "compose" ... }
Chaining
You can use ludash method chaining (also known as name parameter idiom) which is a technique for invoking consecutively method calls in object-oriented style. Each method returns an object, and methods calls are chained together.
chain(value)
Returns a wrapped table. Calling methods on this table will continue to return wrapped tables until :value()
is used to unwrap a chained object.
For convenience, you can also use _(value)
to start chaining methods, instead of _.chain(value)
.
local stooges = {{name='curly', age=25}, {name='moe', age=21}, {name='larry', age=23}}local youngest = _.chain(stooges) :sortBy(function (stooge) return stooge.age end) :map(function (stooge) return stooge.name .. ' is ' .. stooge.age end) :first() :value()-- => "moe is 21"
value()
Extracts the value of a wrapped chained object.
_({1, 2, 3}):value();-- => {1, 2, 3}
References
License
MIT Licensed
Copyright (c) 2014 Dmitri Voronianski [email protected]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.