diff options
author | Yonaba <roland.yonaba@gmail.com> | 2018-09-12 14:59:02 +0300 |
---|---|---|
committer | Yonaba <roland.yonaba@gmail.com> | 2018-09-12 14:59:02 +0300 |
commit | 1f0f01b8ae5297671ff7767b3ca7952293b67137 (patch) | |
tree | 476b1bd6a3f58fe416dcf59f0f11c9164f13b873 | |
parent | ab8827720f20482f9af6b794e5efca5ad6b8a209 (diff) |
Bump to 2.1.0 (see CHANGELOG)
-rw-r--r-- | CHANGELOG.md | 65 | ||||
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | doc/index.html | 1240 | ||||
-rw-r--r-- | doc/manual/tutorial.md.html | 489 | ||||
-rw-r--r-- | doc/tutorial.md | 429 | ||||
-rw-r--r-- | moses.lua | 607 | ||||
-rw-r--r-- | moses_min.lua | 878 | ||||
-rw-r--r-- | spec/array_spec.lua | 74 | ||||
-rw-r--r-- | spec/func_spec.lua | 167 | ||||
-rw-r--r-- | spec/object_spec.lua | 56 | ||||
-rw-r--r-- | spec/table_spec.lua | 113 |
11 files changed, 3154 insertions, 969 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a827f8e..df75682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,70 @@ # Version history +## 2.1.0 (09/12/2018) + +### Breaking changes + +* Renamed `toArray` to `pack` +* Renamed `reduceby` to `reduceBy` +* Removed `skip` as alias to `last` +* Changed prototype : `each(t, f, ...)` is now `each(t, f)` +* Changed prototype : `eachi(t, f, ...)` is now `eachi(t, f)` +* Changed prototype : `adjust(t, key, f, ...)` is now `adjust(t, key, f)` +* Changed prototype : `countf(t, f, ...)` is now `countf(t, f)` +* Changed prototype : `map(t, f, ...)` is now `map(t, f)` +* Changed prototype : `reduceBy(t, f, pred, state, ...)` is now `reduceBy(t, f, pred, state)` +* Changed prototype : `select(t, f, ...)` is now `select(t, f)` +* Changed prototype : `reject(t, f, ...)` is now `reject(t, f)` +* Changed prototype : `all(t, f, ...)` is now `all(t, f)` +* Changed prototype : `invoke(t, method, ...)` is now `invoke(t, method)` +* Changed prototype : `min(t, transform, ...)` is now `min(t, transform)` +* Changed prototype : `max(t, transform, ...)` is now `max(t, transform)` +* Changed prototype : `countBy(t, iter, ...)` is now `countBy(t, iter)` +* Changed prototype : `groupBy(t, iter, ...)` is now `groupBy(t, iter)` +* Changed prototype : `selectWhile(array, f, ...)` is now `selectWhile(array, f)` +* Changed prototype : `dropWhile(array, f, ...)` is now `dropWhile(array, f)` +* Changed prototype : `findIndex(array, pred, ...)` is now `findIndex(array, pred)` +* Changed prototype : `findLastIndex(array, pred, ...)` is now `findLastIndex(array, pred)` +* Changed prototype : `chunk(array, f, ...)` is now `chunk(array, f)` +* Changed prototype : `times(iter, n, ...)` is now `times(iter, n)` +* Changed prototype : `template(id, ...)` is now `template(id)` +* Changed prototype : `tap(obj, f, ...)` is now `tap(obj, f)` +* Changed prototype : `result(obj, method, ...)` is now `result(obj, method)` + +### Other changes + +* Renamed `array` to `tabulate`, with no alias +* Moved `invert` to object functions + +### Additions + +* Added `best` in table functions +* Added `allEqual` in table functions +* Added `sortedk` iterator in array functions +* Added `sortedv` iterator in array functions +* Added `disjoint` in array functions +* Added `nsorted` in array functions +* Added `duplicates` in array functions +* Added `xpairs` in array functions +* Added `xpairsRight` in array functions +* Added `call` in utility functions +* Added `type` in object functions +* Added `spreadPath` in object functions +* Added `flattenPath` in object functions +* Added `thread` in utility functions +* Added `threadRight` in utility functions +* Added `iterlen` in utility functions +* Added `skip` in utility functions +* Added `both` in utility functions +* Added `either` in utility functions +* Added `neither` in utility functions +* Added `dispatch` in utility functions +* Added `noarg` in utility functions + +### Changes + +* Changed `intersection` prototype : `intersection(array,...)` becomes `intersection(...)` + ## 2.0.0 (08/23/2018) ### Breaking changes * library functions now accept iterators prototyped as `f(v, k, ...)` instead of `f(k, v, ...)`. @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.org/Yonaba/Moses.png)](https://travis-ci.org/Yonaba/Moses) +[![Latest Stable](https://img.shields.io/badge/Latest_Stable-2.1.0-blue.svg) [![License](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE) [![Lua](https://img.shields.io/badge/Lua-5.1%2C%205.2%2C%205.3%2C%20JIT-blue.svg)]() @@ -47,7 +48,7 @@ Feel free to download and try it on your own! ## Download ### Archive -* __2.0.0__ *(latest stable)*: [zip](http://github.com/Yonaba/Moses/archive/Moses-2.0.0-1.zip) | [tar.gz](http://github.com/Yonaba/Moses/archive/Moses-2.0.0-1.tar.gz) +* __2.1.0__ *(latest stable)*: [zip](http://github.com/Yonaba/Moses/archive/Moses-2.1.0-1.zip) | [tar.gz](http://github.com/Yonaba/Moses/archive/Moses-2.1.0-1.tar.gz) * __Previous versions__ : [tags](http://github.com/Yonaba/Moses/tags) ### Bash @@ -74,7 +75,7 @@ moonrocks install moses local M = require "moses" ```` -*Note:* the full source [moses.lua](https://github.com/Yonaba/Moses/blob/master/moses.lua) is quite heavy (~83 kiB, 2780 LOC). You can alternatively use the [minified version](https://github.com/Yonaba/Moses/blob/master/moses_min.lua) (~32 kiB, 521 LOC). +*Note:* the full source [moses.lua](https://github.com/Yonaba/Moses/blob/master/moses.lua) is quite heavy (~92 kiB, 3115 LOC). You can alternatively use the [minified version](https://github.com/Yonaba/Moses/blob/master/moses_min.lua) (~35 kiB, 561 LOC). ## Tutorial diff --git a/doc/index.html b/doc/index.html index 8dee3c0..847cee5 100644 --- a/doc/index.html +++ b/doc/index.html @@ -58,7 +58,7 @@ <h3>Info:</h3> <ul> <li><strong>Copyright</strong>: 2012-2018</li> - <li><strong>Release</strong>: 2.0.0</li> + <li><strong>Release</strong>: 2.1.0</li> <li><strong>License</strong>: <a href="http://www.opensource.org/licenses/mit-license.php">MIT</a></li> <li><strong>Author</strong>: <a href="http://github.com/Yonaba">Roland Yonaba</a></li> </ul> @@ -150,18 +150,26 @@ <h2><a href="#Table_functions">Table functions </a></h2> <table class="function_list"> <tr> - <td class="name" nowrap><a href="#adjust">adjust (t, key, f[, ...])</a></td> + <td class="name" nowrap><a href="#adjust">adjust (t, key, f)</a></td> <td class="summary">Adjusts the value at a given key using a function or a value.</td> </tr> <tr> - <td class="name" nowrap><a href="#all">all (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#all">all (t, f)</a></td> <td class="summary">Checks if all values in a table are passing an iterator test.</td> </tr> <tr> + <td class="name" nowrap><a href="#allEqual">allEqual (t[, comp])</a></td> + <td class="summary">Checks if all values in a collection are equal.</td> + </tr> + <tr> <td class="name" nowrap><a href="#at">at (t, ...)</a></td> <td class="summary">Collects values at given keys and return them wrapped in an array.</td> </tr> <tr> + <td class="name" nowrap><a href="#best">best (t, f)</a></td> + <td class="summary">Returns the best value passing a selector function.</td> + </tr> + <tr> <td class="name" nowrap><a href="#clear">clear (t)</a></td> <td class="summary">Clears a table.</td> </tr> @@ -174,11 +182,11 @@ <td class="summary">Counts occurrences of a given value in a table.</td> </tr> <tr> - <td class="name" nowrap><a href="#countBy">countBy (t, iter[, ...])</a></td> + <td class="name" nowrap><a href="#countBy">countBy (t, iter)</a></td> <td class="summary">Groups values in a collection and counts them.</td> </tr> <tr> - <td class="name" nowrap><a href="#countf">countf (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#countf">countf (t, f)</a></td> <td class="summary">Counts the number of values passing a predicate test.</td> </tr> <tr> @@ -190,11 +198,11 @@ <td class="summary">Performs a linear search for a value in a table.</td> </tr> <tr> - <td class="name" nowrap><a href="#each">each (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#each">each (t, f)</a></td> <td class="summary">Iterates on key-value pairs, calling <code>f (v, k)</code> at every step.</td> </tr> <tr> - <td class="name" nowrap><a href="#eachi">eachi (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#eachi">eachi (t, f)</a></td> <td class="summary">Iterates on integer key-value pairs, calling <code>f(v, k)</code> every step.</td> </tr> <tr> @@ -202,7 +210,7 @@ <td class="summary">Returns the first value having specified keys <code>props</code>.</td> </tr> <tr> - <td class="name" nowrap><a href="#groupBy">groupBy (t, iter[, ...])</a></td> + <td class="name" nowrap><a href="#groupBy">groupBy (t, iter)</a></td> <td class="summary">Splits a table into subsets groups.</td> </tr> <tr> @@ -210,11 +218,11 @@ <td class="summary">Performs a linear search for a value in a table.</td> </tr> <tr> - <td class="name" nowrap><a href="#invoke">invoke (t, method[, ...])</a></td> + <td class="name" nowrap><a href="#invoke">invoke (t, method)</a></td> <td class="summary">Invokes a method on each value in a table.</td> </tr> <tr> - <td class="name" nowrap><a href="#map">map (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#map">map (t, f)</a></td> <td class="summary">Maps <code>f (v, k)</code> on value-key pairs, collects and returns the results.</td> </tr> <tr> @@ -226,11 +234,11 @@ <td class="summary">Reduces a table while saving intermediate states.</td> </tr> <tr> - <td class="name" nowrap><a href="#max">max (t[, transform[, ...]])</a></td> + <td class="name" nowrap><a href="#max">max (t[, transform])</a></td> <td class="summary">Returns the max value in a collection.</td> </tr> <tr> - <td class="name" nowrap><a href="#min">min (t[, transform[, ...]])</a></td> + <td class="name" nowrap><a href="#min">min (t[, transform])</a></td> <td class="summary">Returns the min value in a collection.</td> </tr> <tr> @@ -242,15 +250,15 @@ <td class="summary">Reduces a table, left-to-right.</td> </tr> <tr> - <td class="name" nowrap><a href="#reduceRight">reduceRight (t, f[, state])</a></td> - <td class="summary">Reduces a table, right-to-left.</td> + <td class="name" nowrap><a href="#reduceBy">reduceBy (t, f, pred[, state[, ...]])</a></td> + <td class="summary">Reduces values in a table passing a given predicate.</td> </tr> <tr> - <td class="name" nowrap><a href="#reduceby">reduceby (t, f, pred[, state[, ...]])</a></td> - <td class="summary">Reduces values in a table passing a given predicate.</td> + <td class="name" nowrap><a href="#reduceRight">reduceRight (t, f[, state])</a></td> + <td class="summary">Reduces a table, right-to-left.</td> </tr> <tr> - <td class="name" nowrap><a href="#reject">reject (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#reject">reject (t, f)</a></td> <td class="summary">Clones a table while dropping values passing an iterator test.</td> </tr> <tr> @@ -262,7 +270,7 @@ <td class="summary">Checks if both given tables have the same keys.</td> </tr> <tr> - <td class="name" nowrap><a href="#select">select (t, f[, ...])</a></td> + <td class="name" nowrap><a href="#select">select (t, f)</a></td> <td class="summary">Selects and returns values passing an iterator test.</td> </tr> <tr> @@ -278,6 +286,14 @@ <td class="summary">Sorts a table in-place using a transform.</td> </tr> <tr> + <td class="name" nowrap><a href="#sortedk">sortedk (t[, comp])</a></td> + <td class="summary">Iterates on values with respect to key order.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#sortedv">sortedv (t[, comp])</a></td> + <td class="summary">Iterates on values with respect to values order.</td> + </tr> + <tr> <td class="name" nowrap><a href="#where">where (t, props)</a></td> <td class="summary">Returns all values having specified keys <code>props</code>.</td> </tr> @@ -297,7 +313,7 @@ <td class="summary">Clones array and appends values from another array.</td> </tr> <tr> - <td class="name" nowrap><a href="#chunk">chunk (array, f[, ...])</a></td> + <td class="name" nowrap><a href="#chunk">chunk (array, f)</a></td> <td class="summary">Chunks together consecutive values.</td> </tr> <tr> @@ -313,10 +329,18 @@ <td class="summary">Returns values from an array not present in all passed-in args.</td> </tr> <tr> - <td class="name" nowrap><a href="#dropWhile">dropWhile (array, f[, ...])</a></td> + <td class="name" nowrap><a href="#disjoint">disjoint (...)</a></td> + <td class="summary">Checks if all passed in arrays are disjunct.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#dropWhile">dropWhile (array, f)</a></td> <td class="summary">Collects values from a given array.</td> </tr> <tr> + <td class="name" nowrap><a href="#duplicates">duplicates (array)</a></td> + <td class="summary">Returns an array list of all duplicates in array.</td> + </tr> + <tr> <td class="name" nowrap><a href="#fill">fill (array, value[, i[, j]])</a></td> <td class="summary">Replaces elements in a given array with a given value.</td> </tr> @@ -325,11 +349,11 @@ <td class="summary">Looks for the first occurrence of a given value in an array.</td> </tr> <tr> - <td class="name" nowrap><a href="#findIndex">findIndex (array, predicate[, ...])</a></td> + <td class="name" nowrap><a href="#findIndex">findIndex (array, pred)</a></td> <td class="summary">Returns the first index at which a predicate returns true.</td> </tr> <tr> - <td class="name" nowrap><a href="#findLastIndex">findLastIndex (array, predicate[, ...])</a></td> + <td class="name" nowrap><a href="#findLastIndex">findLastIndex (array, pred)</a></td> <td class="summary">Returns the last index at which a predicate returns true.</td> </tr> <tr> @@ -357,14 +381,10 @@ <td class="summary">Interposes value in-between consecutive pair of values in array.</td> </tr> <tr> - <td class="name" nowrap><a href="#intersection">intersection (array, ...)</a></td> + <td class="name" nowrap><a href="#intersection">intersection (...)</a></td> <td class="summary">Returns the intersection of all passed-in arrays.</td> </tr> <tr> - <td class="name" nowrap><a href="#invert">invert (array)</a></td> - <td class="summary">Swaps keys with values.</td> - </tr> - <tr> <td class="name" nowrap><a href="#isunique">isunique (array)</a></td> <td class="summary">Checks if a given array contains distinct values.</td> </tr> @@ -385,6 +405,10 @@ <td class="summary">Returns the median of an array of numbers.</td> </tr> <tr> + <td class="name" nowrap><a href="#nsorted">nsorted (array[, n[, comp]])</a></td> + <td class="summary">Returns the n-top values satisfying a predicate.</td> + </tr> + <tr> <td class="name" nowrap><a href="#nth">nth (array, index)</a></td> <td class="summary">Returns the value at a given index.</td> </tr> @@ -397,6 +421,10 @@ <td class="summary">Iterator returning overlapping partitions of an array.</td> </tr> <tr> + <td class="name" nowrap><a href="#pack">pack (...)</a></td> + <td class="summary">Converts a list of arguments to an array.</td> + </tr> + <tr> <td class="name" nowrap><a href="#pairwise">pairwise (array)</a></td> <td class="summary">Iterator returning sliding pairs of an array.</td> </tr> @@ -457,7 +485,7 @@ <td class="summary">Return elements from a sequence with a given probability.</td> </tr> <tr> - <td class="name" nowrap><a href="#selectWhile">selectWhile (array, f[, ...])</a></td> + <td class="name" nowrap><a href="#selectWhile">selectWhile (array, f)</a></td> <td class="summary">Collects values from a given array.</td> </tr> <tr> @@ -485,10 +513,6 @@ <td class="summary">Performs a symmetric difference.</td> </tr> <tr> - <td class="name" nowrap><a href="#toArray">toArray (...)</a></td> - <td class="summary">Converts a list of arguments to an array.</td> - </tr> - <tr> <td class="name" nowrap><a href="#union">union (...)</a></td> <td class="summary">Returns the duplicate-free union of all passed in arrays.</td> </tr> @@ -505,6 +529,14 @@ <td class="summary">Returns an array of <code>n</code> times a given value.</td> </tr> <tr> + <td class="name" nowrap><a href="#xpairs">xpairs (valua, array)</a></td> + <td class="summary">Creates pairs from value and array.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#xpairsRight">xpairsRight (valua, array)</a></td> + <td class="summary">Creates pairs from value and array.</td> + </tr> + <tr> <td class="name" nowrap><a href="#xprod">xprod (array, array2)</a></td> <td class="summary">Returns all possible pairs built from given arrays.</td> </tr> @@ -532,10 +564,6 @@ <td class="summary">Returns a function which applies <code>specs</code> on args.</td> </tr> <tr> - <td class="name" nowrap><a href="#array">array (...)</a></td> - <td class="summary">Iterates over an iterator and returns its values in an array.</td> - </tr> - <tr> <td class="name" nowrap><a href="#ary">ary (f[, n])</a></td> <td class="summary">Returns a function which accepts up to <code>n</code> args.</td> </tr> @@ -560,8 +588,16 @@ <td class="summary">Binds <code>...</code> to be the N-first arguments to function <code>f</code>.</td> </tr> <tr> + <td class="name" nowrap><a href="#both">both (...)</a></td> + <td class="summary">Returns a validation function.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#call">call (f[, ...])</a></td> + <td class="summary">Calls <code>f</code> with the supplied arguments.</td> + </tr> + <tr> <td class="name" nowrap><a href="#castArray">castArray (value)</a></td> - <td class="summary">Casts vaue as an array if it is not one.</td> + <td class="summary">Casts value as an array if it is not one.</td> </tr> <tr> <td class="name" nowrap><a href="#complement">complement (f)</a></td> @@ -588,6 +624,14 @@ <td class="summary">Curries a function.</td> </tr> <tr> + <td class="name" nowrap><a href="#dispatch">dispatch (...)</a></td> + <td class="summary">Returns a dispatching function.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#either">either (...)</a></td> + <td class="summary">Returns a validation function.</td> + </tr> + <tr> <td class="name" nowrap><a href="#flip">flip (f)</a></td> <td class="summary">Creates a function of <code>f</code> with arguments flipped in reverse order.</td> </tr> @@ -600,6 +644,10 @@ <td class="summary">Produces an iterator which repeatedly apply a function <code>f</code> onto an input.</td> </tr> <tr> + <td class="name" nowrap><a href="#iterlen">iterlen (...)</a></td> + <td class="summary">Returns the length of an iterator.</td> + </tr> + <tr> <td class="name" nowrap><a href="#juxtapose">juxtapose (value, ...)</a></td> <td class="summary">Calls a sequence of passed-in functions with the same argument.</td> </tr> @@ -608,6 +656,14 @@ <td class="summary">Memoizes a given function by caching the computed result.</td> </tr> <tr> + <td class="name" nowrap><a href="#neither">neither (...)</a></td> + <td class="summary">Returns a validation function.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#noarg">noarg (f)</a></td> + <td class="summary">Returns a function with an arity of 0.</td> + </tr> + <tr> <td class="name" nowrap><a href="#noop">noop ()</a></td> <td class="summary">The no operation function.</td> </tr> @@ -652,11 +708,27 @@ <td class="summary">Returns a function which runs with arguments rearranged.</td> </tr> <tr> + <td class="name" nowrap><a href="#skip">skip (iter[, n])</a></td> + <td class="summary">Consumes the first <code>n</code> values of a iterator then returns it.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#tabulate">tabulate (...)</a></td> + <td class="summary">Iterates over an iterator and returns its values in an array.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#thread">thread (value, ...)</a></td> + <td class="summary">Threads <a href="index.html#obj:value">value</a> through a series of functions.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#threadRight">threadRight (value, ...)</a></td> + <td class="summary">Threads <a href="index.html#obj:value">value</a> through a series of functions.</td> + </tr> + <tr> <td class="name" nowrap><a href="#time">time (f[, ...])</a></td> <td class="summary">Returns the execution time of <code>f (...)</code> and its returned values.</td> </tr> <tr> - <td class="name" nowrap><a href="#times">times (iter[, n[, ...]])</a></td> + <td class="name" nowrap><a href="#times">times (iter[, n])</a></td> <td class="summary">Runs <code>iter</code> function <code>n</code> times.</td> </tr> <tr> @@ -668,7 +740,7 @@ <td class="summary">Builds a list from a seed value.</td> </tr> <tr> - <td class="name" nowrap><a href="#uniqueId">uniqueId ([template[, ...]])</a></td> + <td class="name" nowrap><a href="#uniqueId">uniqueId ([template])</a></td> <td class="summary">Generates an unique ID for the current session.</td> </tr> <tr> @@ -691,6 +763,10 @@ <td class="summary">Extends an object properties.</td> </tr> <tr> + <td class="name" nowrap><a href="#flattenPath">flattenPath (obj, ...)</a></td> + <td class="summary">Flattens object under property path onto provided object.</td> + </tr> + <tr> <td class="name" nowrap><a href="#functions">functions ([obj])</a></td> <td class="summary">Returns a sorted list of all methods names found in an object.</td> </tr> @@ -703,6 +779,10 @@ <td class="summary">Imports all library functions into a context.</td> </tr> <tr> + <td class="name" nowrap><a href="#invert">invert (obj)</a></td> + <td class="summary">Swaps keys with values.</td> + </tr> + <tr> <td class="name" nowrap><a href="#isArray">isArray (obj)</a></td> <td class="summary">Checks if the given argument is an array.</td> </tr> @@ -791,11 +871,15 @@ <td class="summary">Returns a function which will return the value of an object property.</td> </tr> <tr> - <td class="name" nowrap><a href="#result">result (obj, method[, ...])</a></td> + <td class="name" nowrap><a href="#result">result (obj, method)</a></td> <td class="summary">Invokes an object method.</td> </tr> <tr> - <td class="name" nowrap><a href="#tap">tap (obj, f[, ...])</a></td> + <td class="name" nowrap><a href="#spreadPath">spreadPath (obj, ...)</a></td> + <td class="summary">Spreads object under property path onto provided object.</td> + </tr> + <tr> + <td class="name" nowrap><a href="#tap">tap (obj, f)</a></td> <td class="summary">Invokes interceptor with the object, and then returns object.</td> </tr> <tr> @@ -811,6 +895,10 @@ <td class="summary">Converts an array list of <code>[k,v]</code> pairs to an object.</td> </tr> <tr> + <td class="name" nowrap><a href="#type">type (obj)</a></td> + <td class="summary">Extends Lua's <a href="index.html#type">type</a> function.</td> + </tr> + <tr> <td class="name" nowrap><a href="#values">values (obj)</a></td> <td class="summary">Returns the values of the object properties.</td> </tr> @@ -1383,11 +1471,11 @@ <dl class="function"> <dt> <a name = "adjust"></a> - <strong>adjust (t, key, f[, ...])</strong> + <strong>adjust (t, key, f)</strong> </dt> <dd> Adjusts the value at a given key using a function or a value. In case <code>f</code> is a function, - it should be prototyped <code>f(v, ...)</code>. It does not mutate the given table, but rather + it should be prototyped <code>f(v)</code>. It does not mutate the given table, but rather returns a new array. In case the given <code>key</code> does not exist in <code>t</code>, it throws an error. @@ -1400,11 +1488,7 @@ a key </li> <li><span class="parameter">f</span> - a function, prototyped as <code>f(v, ...)</code> or a value - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + a function, prototyped as <code>f(v)</code> or a value </li> </ul> @@ -1415,7 +1499,7 @@ </dd> <dt> <a name = "all"></a> - <strong>all (t, f[, ...])</strong> + <strong>all (t, f)</strong> </dt> <dd> Checks if all values in a table are passing an iterator test. @@ -1428,10 +1512,37 @@ a table </li> <li><span class="parameter">f</span> - an iterator function, prototyped as <code>f (v, k, ...)</code> + an iterator function, prototyped as <code>f (v, k)</code> </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> + </ul> + + <h3>Returns:</h3> + <ol> + + <code>true</code> if all values passes the predicate, <code>false</code> otherwise + </ol> + + + + +</dd> + <dt> + <a name = "allEqual"></a> + <strong>allEqual (t[, comp])</strong> + </dt> + <dd> + Checks if all values in a collection are equal. Uses an optional <code>comp</code> function which is used + to compare values and defaults to <a href="index.html#isEqual">isEqual</a> when not given. + <br/><em>Aliased as <code>alleq</code></em>. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">t</span> + a table + </li> + <li><span class="parameter">comp</span> + a comparison function. Defaults to <a href="index.html#isEqual">isEqual</a> (<em>optional</em>) </li> </ul> @@ -1439,10 +1550,14 @@ <h3>Returns:</h3> <ol> - <code>true</code> if all values passes the predicate, <code>false</code> otherwise + <code>true</code> when all values in <code>t</code> are equal, <code>false</code> otherwise. </ol> + <h3>See also:</h3> + <ul> + <a href="index.html#isEqual">isEqual</a> + </ul> </dd> @@ -1475,6 +1590,42 @@ </dd> <dt> + <a name = "best"></a> + <strong>best (t, f)</strong> + </dt> + <dd> + Returns the best value passing a selector function. Acts as a special case of + <a href="index.html#reduce">reduce</a>, using the first value in <code>t</code> as an initial state. It thens folds the given table, + testing each of its values <code>v</code> and selecting the value passing the call <code>f(state,v)</code> every time. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">t</span> + a table + </li> + <li><span class="parameter">f</span> + an iterator function, prototyped as <code>f (state, value)</code> + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the final state of reduction + </ol> + + + <h3>See also:</h3> + <ul> + <li><a href="index.html#reduce">reduce</a></li> + <li><a href="index.html#reduceRight">reduceRight</a></li> + <li><a href="index.html#reduceBy">reduceBy</a></li> + </ul> + + +</dd> + <dt> <a name = "clear"></a> <strong>clear (t)</strong> </dt> @@ -1569,7 +1720,7 @@ </dd> <dt> <a name = "countBy"></a> - <strong>countBy (t, iter[, ...])</strong> + <strong>countBy (t, iter)</strong> </dt> <dd> Groups values in a collection and counts them. @@ -1581,11 +1732,7 @@ a table </li> <li><span class="parameter">iter</span> - an iterator function, prototyped as <code>iter (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>iter</code> - (<em>optional</em>) + an iterator function, prototyped as <code>iter (v, k)</code> </li> </ul> @@ -1601,11 +1748,11 @@ </dd> <dt> <a name = "countf"></a> - <strong>countf (t, f[, ...])</strong> + <strong>countf (t, f)</strong> </dt> <dd> Counts the number of values passing a predicate test. Same as <a href="index.html#count">count</a>, but uses an iterator. - Returns the count for values passing the test <code>f (v, k, ...)</code> + Returns the count for values passing the test <code>f (v, k)</code> <h3>Parameters:</h3> @@ -1614,11 +1761,7 @@ a table </li> <li><span class="parameter">f</span> - an iterator function, prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function, prototyped as <code>f (v, k)</code> </li> </ul> @@ -1706,7 +1849,7 @@ </dd> <dt> <a name = "each"></a> - <strong>each (t, f[, ...])</strong> + <strong>each (t, f)</strong> </dt> <dd> Iterates on key-value pairs, calling <code>f (v, k)</code> at every step. @@ -1719,11 +1862,7 @@ a table </li> <li><span class="parameter">f</span> - a function, prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + a function, prototyped as <code>f (v, k)</code> </li> </ul> @@ -1738,7 +1877,7 @@ </dd> <dt> <a name = "eachi"></a> - <strong>eachi (t, f[, ...])</strong> + <strong>eachi (t, f)</strong> </dt> <dd> Iterates on integer key-value pairs, calling <code>f(v, k)</code> every step. <br/> @@ -1753,11 +1892,7 @@ a table </li> <li><span class="parameter">f</span> - a function, prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + a function, prototyped as <code>f (v, k)</code> </li> </ul> @@ -1804,7 +1939,7 @@ </dd> <dt> <a name = "groupBy"></a> - <strong>groupBy (t, iter[, ...])</strong> + <strong>groupBy (t, iter)</strong> </dt> <dd> Splits a table into subsets groups. @@ -1816,11 +1951,7 @@ a table </li> <li><span class="parameter">iter</span> - an iterator function, prototyped as <code>iter (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>iter</code> - (<em>optional</em>) + an iterator function, prototyped as <code>iter (v, k)</code> </li> </ul> @@ -1871,7 +2002,7 @@ </dd> <dt> <a name = "invoke"></a> - <strong>invoke (t, method[, ...])</strong> + <strong>invoke (t, method)</strong> </dt> <dd> Invokes a method on each value in a table. @@ -1883,18 +2014,14 @@ a table </li> <li><span class="parameter">method</span> - a function, prototyped as <code>f (v, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>method</code> - (<em>optional</em>) + a function, prototyped as <code>f (v, k)</code> </li> </ul> <h3>Returns:</h3> <ol> - the result of the call <code>f (v, ...)</code> + the result of the call <code>f (v, k)</code> </ol> @@ -1907,7 +2034,7 @@ </dd> <dt> <a name = "map"></a> - <strong>map (t, f[, ...])</strong> + <strong>map (t, f)</strong> </dt> <dd> Maps <code>f (v, k)</code> on value-key pairs, collects and returns the results. @@ -1920,11 +2047,7 @@ a table </li> <li><span class="parameter">f</span> - an iterator function, prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function, prototyped as <code>f (v, k)</code> </li> </ul> @@ -2018,7 +2141,7 @@ </dd> <dt> <a name = "max"></a> - <strong>max (t[, transform[, ...]])</strong> + <strong>max (t[, transform])</strong> </dt> <dd> Returns the max value in a collection. If a <code>transform</code> function is passed, it will @@ -2031,11 +2154,7 @@ a table </li> <li><span class="parameter">transform</span> - a transformation function, prototyped as <code>transform (v, ...)</code>, defaults to <a href="index.html#identity">identity</a> - (<em>optional</em>) - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>transform</code> + a transformation function, prototyped as <code>transform (v, k)</code>, defaults to <a href="index.html#identity">identity</a> (<em>optional</em>) </li> </ul> @@ -2056,7 +2175,7 @@ </dd> <dt> <a name = "min"></a> - <strong>min (t[, transform[, ...]])</strong> + <strong>min (t[, transform])</strong> </dt> <dd> Returns the min value in a collection. If a <code>transform</code> function is passed, it will @@ -2069,11 +2188,7 @@ a table </li> <li><span class="parameter">transform</span> - a transformation function, prototyped as <code>transform (v, ...)</code>, defaults to <a href="index.html#identity">identity</a> - (<em>optional</em>) - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>transform</code> + a transformation function, prototyped as <code>transform (v, k)</code>, defaults to <a href="index.html#identity">identity</a> (<em>optional</em>) </li> </ul> @@ -2154,21 +2269,20 @@ <h3>See also:</h3> <ul> + <li><a href="index.html#best">best</a></li> <li><a href="index.html#reduceRight">reduceRight</a></li> - <li><a href="index.html#reduceby">reduceby</a></li> + <li><a href="index.html#reduceBy">reduceBy</a></li> </ul> </dd> <dt> - <a name = "reduceRight"></a> - <strong>reduceRight (t, f[, state])</strong> + <a name = "reduceBy"></a> + <strong>reduceBy (t, f, pred[, state[, ...]])</strong> </dt> <dd> - Reduces a table, right-to-left. Folds the table from the last element to the first element - to single value, using a given iterator and an initial state. - The iterator takes a state and a value, and returns a new state. - <br/><em>Aliased as <code>injectr</code>, <code>foldr</code></em>. + Reduces values in a table passing a given predicate. Folds the table left-to-right, considering + only values validating a given predicate. <h3>Parameters:</h3> @@ -2179,8 +2293,15 @@ <li><span class="parameter">f</span> an iterator function, prototyped as <code>f (state, value)</code> </li> + <li><span class="parameter">pred</span> + a predicate function <code>pred (v, k)</code> to select values to be considered for reduction + </li> <li><span class="parameter">state</span> - an initial state of reduction. Defaults to the last value in the table. + an initial state of reduction. Defaults to the first value in the table of selected values. + (<em>optional</em>) + </li> + <li><span class="parameter">...</span> + optional args to be passed to <code>pred</code> (<em>optional</em>) </li> </ul> @@ -2194,18 +2315,22 @@ <h3>See also:</h3> <ul> - <a href="index.html#reduce">reduce</a> + <li><a href="index.html#reduce">reduce</a></li> + <li><a href="index.html#best">best</a></li> + <li><a href="index.html#reduceRight">reduceRight</a></li> </ul> </dd> <dt> - <a name = "reduceby"></a> - <strong>reduceby (t, f, pred[, state[, ...]])</strong> + <a name = "reduceRight"></a> + <strong>reduceRight (t, f[, state])</strong> </dt> <dd> - Reduces values in a table passing a given predicate. Folds the table left-to-right, considering - only values validating a given predicate. + Reduces a table, right-to-left. Folds the table from the last element to the first element + to single value, using a given iterator and an initial state. + The iterator takes a state and a value, and returns a new state. + <br/><em>Aliased as <code>injectr</code>, <code>foldr</code></em>. <h3>Parameters:</h3> @@ -2216,15 +2341,8 @@ <li><span class="parameter">f</span> an iterator function, prototyped as <code>f (state, value)</code> </li> - <li><span class="parameter">pred</span> - a predicate function <code>pred (v, k, ...)</code> to select values to be considered for reduction - </li> <li><span class="parameter">state</span> - an initial state of reduction. Defaults to the first value in the table of selected values. - (<em>optional</em>) - </li> - <li><span class="parameter">...</span> - optional args to be passed to <code>pred</code> + an initial state of reduction. Defaults to the last value in the table. (<em>optional</em>) </li> </ul> @@ -2238,14 +2356,16 @@ <h3>See also:</h3> <ul> - <a href="index.html#reduce">reduce</a> + <li><a href="index.html#reduce">reduce</a></li> + <li><a href="index.html#best">best</a></li> + <li><a href="index.html#reduceBy">reduceBy</a></li> </ul> </dd> <dt> <a name = "reject"></a> - <strong>reject (t, f[, ...])</strong> + <strong>reject (t, f)</strong> </dt> <dd> Clones a table while dropping values passing an iterator test. @@ -2258,11 +2378,7 @@ a table </li> <li><span class="parameter">f</span> - an iterator function, prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function, prototyped as <code>f (v, k)</code> </li> </ul> @@ -2343,7 +2459,7 @@ </dd> <dt> <a name = "select"></a> - <strong>select (t, f[, ...])</strong> + <strong>select (t, f)</strong> </dt> <dd> Selects and returns values passing an iterator test. @@ -2356,11 +2472,7 @@ a table </li> <li><span class="parameter">f</span> - an iterator function, prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function, prototyped as <code>f (v, k)</code> </li> </ul> @@ -2483,6 +2595,74 @@ </dd> <dt> + <a name = "sortedk"></a> + <strong>sortedk (t[, comp])</strong> + </dt> + <dd> + Iterates on values with respect to key order. Keys are sorted using <code>comp</code> function + which defaults to <a href="https://www.lua.org/manual/5.1/manual.html#pdf-math.min">math.min</a>. It returns upon each call a <code>key, value</code> pair. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">t</span> + a table + </li> + <li><span class="parameter">comp</span> + a comparison function. Defaults to <code><</code> operator + (<em>optional</em>) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an iterator function + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#sortedv">sortedv</a> + </ul> + + +</dd> + <dt> + <a name = "sortedv"></a> + <strong>sortedv (t[, comp])</strong> + </dt> + <dd> + Iterates on values with respect to values order. Values are sorted using <code>comp</code> function + which defaults to <a href="https://www.lua.org/manual/5.1/manual.html#pdf-math.min">math.min</a>. It returns upon each call a <code>key, value</code> pair. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">t</span> + a table + </li> + <li><span class="parameter">comp</span> + a comparison function. Defaults to <code><</code> operator + (<em>optional</em>) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an iterator function + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#sortedk">sortedk</a> + </ul> + + +</dd> + <dt> <a name = "where"></a> <strong>where (t, props)</strong> </dt> @@ -2618,11 +2798,11 @@ </dd> <dt> <a name = "chunk"></a> - <strong>chunk (array, f[, ...])</strong> + <strong>chunk (array, f)</strong> </dt> <dd> Chunks together consecutive values. Values are chunked on the basis of the return - value of a provided predicate <code>f (k, v, ...)</code>. Consecutive elements which return + value of a provided predicate <code>f (v, k)</code>. Consecutive elements which return the same value are chunked together. Leaves the first argument untouched if it is not an array. @@ -2632,11 +2812,7 @@ an array </li> <li><span class="parameter">f</span> - an iterator function prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function prototyped as <code>f (v, k)</code> </li> </ul> @@ -2755,8 +2931,37 @@ </dd> <dt> + <a name = "disjoint"></a> + <strong>disjoint (...)</strong> + </dt> + <dd> + Checks if all passed in arrays are disjunct. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + a variable number of arrays + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + <code>true</code> if the intersection of all arrays is not empty, <code>false</code> otherwise. + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#intersection">intersection</a> + </ul> + + +</dd> + <dt> <a name = "dropWhile"></a> - <strong>dropWhile (array, f[, ...])</strong> + <strong>dropWhile (array, f)</strong> </dt> <dd> Collects values from a given array. The passed-in array should not be sparse. @@ -2770,11 +2975,7 @@ an array </li> <li><span class="parameter">f</span> - an iterator function prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function prototyped as <code>f (v, k)</code> </li> </ul> @@ -2793,6 +2994,35 @@ </dd> <dt> + <a name = "duplicates"></a> + <strong>duplicates (array)</strong> + </dt> + <dd> + Returns an array list of all duplicates in array. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">array</span> + an array + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an array-list of duplicates + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#unique">unique</a> + </ul> + + +</dd> + <dt> <a name = "fill"></a> <strong>fill (array, value[, i[, j]])</strong> </dt> @@ -2869,7 +3099,7 @@ </dd> <dt> <a name = "findIndex"></a> - <strong>findIndex (array, predicate[, ...])</strong> + <strong>findIndex (array, pred)</strong> </dt> <dd> Returns the first index at which a predicate returns true. @@ -2880,12 +3110,8 @@ <li><span class="parameter">array</span> an array </li> - <li><span class="parameter">predicate</span> - a predicate function prototyped as <code>predicate (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - optional arguments to <code>pred</code> - (<em>optional</em>) + <li><span class="parameter">pred</span> + a predicate function prototyped as <code>pred (v, k)</code> </li> </ul> @@ -2905,7 +3131,7 @@ </dd> <dt> <a name = "findLastIndex"></a> - <strong>findLastIndex (array, predicate[, ...])</strong> + <strong>findLastIndex (array, pred)</strong> </dt> <dd> Returns the last index at which a predicate returns true. @@ -2916,12 +3142,8 @@ <li><span class="parameter">array</span> an array </li> - <li><span class="parameter">predicate</span> - a predicate function prototyped as <code>predicate (k, v, ...)</code> - </li> - <li><span class="parameter">...</span> - optional arguments to <code>pred</code> - (<em>optional</em>) + <li><span class="parameter">pred</span> + a predicate function prototyped as <code>pred (k, v)</code> </li> </ul> @@ -3136,7 +3358,7 @@ </dd> <dt> <a name = "intersection"></a> - <strong>intersection (array, ...)</strong> + <strong>intersection (...)</strong> </dt> <dd> Returns the intersection of all passed-in arrays. @@ -3145,9 +3367,6 @@ <h3>Parameters:</h3> <ul> - <li><span class="parameter">array</span> - an array - </li> <li><span class="parameter">...</span> a variable number of array arguments </li> @@ -3170,33 +3389,6 @@ </dd> <dt> - <a name = "invert"></a> - <strong>invert (array)</strong> - </dt> - <dd> - Swaps keys with values. Produces a new array where previous keys are now values, - while previous values are now keys. - <br/><em>Aliased as <code>mirror</code></em> - - - <h3>Parameters:</h3> - <ul> - <li><span class="parameter">array</span> - a given array - </li> - </ul> - - <h3>Returns:</h3> - <ol> - - a new array - </ol> - - - - -</dd> - <dt> <a name = "isunique"></a> <strong>isunique (array)</strong> </dt> @@ -3222,7 +3414,8 @@ <h3>See also:</h3> <ul> - <a href="index.html#unique">unique</a> + <li><a href="index.html#unique">unique</a></li> + <li><a href="index.html#duplicates">duplicates</a></li> </ul> @@ -3358,6 +3551,40 @@ </dd> <dt> + <a name = "nsorted"></a> + <strong>nsorted (array[, n[, comp]])</strong> + </dt> + <dd> + Returns the n-top values satisfying a predicate. It takes a comparison function + <code>comp</code> used to sort array values, and then picks the top n-values. It leaves the original array untouched. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">array</span> + an array + </li> + <li><span class="parameter">n</span> + a number of values to retrieve. Defaults to 1. + (<em>optional</em>) + </li> + <li><span class="parameter">comp</span> + a comparison function. Defaults to <code><</code> operator. + (<em>optional</em>) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an array of top n values + </ol> + + + + +</dd> + <dt> <a name = "nth"></a> <strong>nth (array, index)</strong> </dt> @@ -3456,6 +3683,31 @@ </dd> <dt> + <a name = "pack"></a> + <strong>pack (...)</strong> + </dt> + <dd> + Converts a list of arguments to an array. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + a list of arguments + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an array of all passed-in args + </ol> + + + + +</dd> + <dt> <a name = "pairwise"></a> <strong>pairwise (array)</strong> </dt> @@ -3582,7 +3834,7 @@ </dt> <dd> Adds all passed-in values at the top of an array. As opposed to <a href="index.html#addTop">addTop</a>, it preserves the order - of the passed in elements. + of the passed-in elements. <h3>Parameters:</h3> @@ -3935,7 +4187,7 @@ </dd> <dt> <a name = "selectWhile"></a> - <strong>selectWhile (array, f[, ...])</strong> + <strong>selectWhile (array, f)</strong> </dt> <dd> Collects values from a given array. The passed-in array should not be sparse. @@ -3949,11 +4201,7 @@ an array </li> <li><span class="parameter">f</span> - an iterator function prototyped as <code>f (v, k, ...)</code> - </li> - <li><span class="parameter">...</span> - Optional args to be passed to <code>f</code> - (<em>optional</em>) + an iterator function prototyped as <code>f (v, k)</code> </li> </ul> @@ -4137,8 +4385,8 @@ <strong>symmetricDifference (array, array2)</strong> </dt> <dd> - Performs a symmetric difference. Returns values from <a href="index.html#array">array</a> not present in <code>array2</code> and also values - from <code>array2</code> not present in <a href="index.html#array">array</a>. + Performs a symmetric difference. Returns values from <code>array</code> not present in <code>array2</code> and also values + from <code>array2</code> not present in <code>array</code>. <br/><em>Aliased as <code>symdiff</code></em> @@ -4169,31 +4417,6 @@ </dd> <dt> - <a name = "toArray"></a> - <strong>toArray (...)</strong> - </dt> - <dd> - Converts a list of arguments to an array. - - - <h3>Parameters:</h3> - <ul> - <li><span class="parameter">...</span> - a list of arguments - </li> - </ul> - - <h3>Returns:</h3> - <ol> - - an array of all passed-in args - </ol> - - - - -</dd> - <dt> <a name = "union"></a> <strong>union (...)</strong> </dt> @@ -4249,7 +4472,8 @@ <h3>See also:</h3> <ul> - <a href="index.html#isunique">isunique</a> + <li><a href="index.html#isunique">isunique</a></li> + <li><a href="index.html#duplicates">duplicates</a></li> </ul> @@ -4321,6 +4545,62 @@ </dd> <dt> + <a name = "xpairs"></a> + <strong>xpairs (valua, array)</strong> + </dt> + <dd> + Creates pairs from value and array. Value is always prepended to the pair. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">valua</span> + a value + </li> + <li><span class="parameter">array</span> + an array + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an array list of all pairs + </ol> + + + + +</dd> + <dt> + <a name = "xpairsRight"></a> + <strong>xpairsRight (valua, array)</strong> + </dt> + <dd> + Creates pairs from value and array. Value is always appended as the last item to the pair. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">valua</span> + a value + </li> + <li><span class="parameter">array</span> + an array + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an array list of all pairs + </ol> + + + + +</dd> + <dt> <a name = "xprod"></a> <strong>xprod (array, array2)</strong> </dt> @@ -4510,32 +4790,6 @@ </dd> <dt> - <a name = "array"></a> - <strong>array (...)</strong> - </dt> - <dd> - Iterates over an iterator and returns its values in an array. - <br/><em>Aliased as <code>tabulate</code></em>. - - - <h3>Parameters:</h3> - <ul> - <li><span class="parameter">...</span> - an iterator function (returning a generator, a state and a value) - </li> - </ul> - - <h3>Returns:</h3> - <ol> - - an array of results - </ol> - - - - -</dd> - <dt> <a name = "ary"></a> <strong>ary (f[, n])</strong> </dt> @@ -4742,11 +4996,66 @@ </dd> <dt> + <a name = "both"></a> + <strong>both (...)</strong> + </dt> + <dd> + Returns a validation function. Given a set of functions, the validation function evaluates + to <code>true</code> only when all its funcs returns <code>true</code>. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + an array list of functions + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + <code>true</code> when all given funcs returns true with input, false otherwise + </ol> + + + + +</dd> + <dt> + <a name = "call"></a> + <strong>call (f[, ...])</strong> + </dt> + <dd> + Calls <code>f</code> with the supplied arguments. Returns the results of <code>f(...)</code>. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">f</span> + a function + </li> + <li><span class="parameter">...</span> + a vararg list of args to <code>f</code> + (<em>optional</em>) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the result of <code>f(...)</code> call. + </ol> + + + + +</dd> + <dt> <a name = "castArray"></a> <strong>castArray (value)</strong> </dt> <dd> - Casts vaue as an array if it is not one. + Casts value as an array if it is not one. <h3>Parameters:</h3> @@ -4944,6 +5253,58 @@ </dd> <dt> + <a name = "dispatch"></a> + <strong>dispatch (...)</strong> + </dt> + <dd> + Returns a dispatching function. When called with arguments, this function invokes each of its functions + in the passed-in order and returns the results of the first non-nil evaluation. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + a vararg list of functions + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + a dispatch function + </ol> + + + + +</dd> + <dt> + <a name = "either"></a> + <strong>either (...)</strong> + </dt> + <dd> + Returns a validation function. Given a set of functions, the validation function evaluates + to <code>true</code> when at least one of its funcs returns <code>true</code>. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + an array list of functions + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + <code>true</code> when one of the given funcs returns <code>true</code> with input, <code>false</code> otherwise + </ol> + + + + +</dd> + <dt> <a name = "flip"></a> <strong>flip (f)</strong> </dt> @@ -5029,6 +5390,31 @@ </dd> <dt> + <a name = "iterlen"></a> + <strong>iterlen (...)</strong> + </dt> + <dd> + Returns the length of an iterator. It consumes the iterator itself. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + an iterator function (returning a generator, a state and a value) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the iterator length + </ol> + + + + +</dd> + <dt> <a name = "juxtapose"></a> <strong>juxtapose (value, ...)</strong> </dt> @@ -5086,6 +5472,57 @@ </dd> <dt> + <a name = "neither"></a> + <strong>neither (...)</strong> + </dt> + <dd> + Returns a validation function. Given a set of functions, the validation function evaluates + to <code>true</code> when neither of its func return <code>true</code>. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + an array list of functions + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + <code>true</code> when neither of the given funcs returns <code>true</code> with input, <code>false</code> otherwise + </ol> + + + + +</dd> + <dt> + <a name = "noarg"></a> + <strong>noarg (f)</strong> + </dt> + <dd> + Returns a function with an arity of 0. The new function ignores any arguments passed to it. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">f</span> + a function + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + a new function + </ol> + + + + +</dd> + <dt> <a name = "noop"></a> <strong>noop ()</strong> </dt> @@ -5423,6 +5860,128 @@ </dd> <dt> + <a name = "skip"></a> + <strong>skip (iter[, n])</strong> + </dt> + <dd> + Consumes the first <code>n</code> values of a iterator then returns it. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">iter</span> + an iterator function + </li> + <li><span class="parameter">n</span> + a number. Defaults to 1. + (<em>optional</em>) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the given iterator + </ol> + + + + +</dd> + <dt> + <a name = "tabulate"></a> + <strong>tabulate (...)</strong> + </dt> + <dd> + Iterates over an iterator and returns its values in an array. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">...</span> + an iterator function (returning a generator, a state and a value) + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + an array of results + </ol> + + + + +</dd> + <dt> + <a name = "thread"></a> + <strong>thread (value, ...)</strong> + </dt> + <dd> + Threads <a href="index.html#obj:value">value</a> through a series of functions. If a function expects more than one args, + it can be specified using an array list, where the first item is the function and the following + are the remaining args neeeded. The value is used as the first input. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">value</span> + a value + </li> + <li><span class="parameter">...</span> + a vararg list of functions or arrays + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + a value + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#threadRight">threadRight</a> + </ul> + + +</dd> + <dt> + <a name = "threadRight"></a> + <strong>threadRight (value, ...)</strong> + </dt> + <dd> + Threads <a href="index.html#obj:value">value</a> through a series of functions. If a function expects more than one args, + it can be specified using an array list, where the first item is the function and the following + are the remaining args neeeded. The value is used as the last input. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">value</span> + a value + </li> + <li><span class="parameter">...</span> + a vararg list of functions or arrays + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + a value + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#thread">thread</a> + </ul> + + +</dd> + <dt> <a name = "time"></a> <strong>time (f[, ...])</strong> </dt> @@ -5453,7 +6012,7 @@ </dd> <dt> <a name = "times"></a> - <strong>times (iter[, n[, ...]])</strong> + <strong>times (iter[, n])</strong> </dt> <dd> Runs <code>iter</code> function <code>n</code> times. Collects the results of each run and returns them in an array. @@ -5462,16 +6021,12 @@ <h3>Parameters:</h3> <ul> <li><span class="parameter">iter</span> - an iterator function, prototyped as <code>iter (i, ...)</code> + an iterator function, prototyped as <code>iter (i)</code> </li> <li><span class="parameter">n</span> the number of times <code>iter</code> should be called. Defaults to 1. (<em>optional</em>) </li> - <li><span class="parameter">...</span> - args to be passed to <code>iter</code> function - (<em>optional</em>) - </li> </ul> <h3>Returns:</h3> @@ -5545,12 +6100,12 @@ </dd> <dt> <a name = "uniqueId"></a> - <strong>uniqueId ([template[, ...]])</strong> + <strong>uniqueId ([template])</strong> </dt> <dd> Generates an unique ID for the current session. If given a string <a href="index.html#template">template</a>, it will use this template for output formatting. Otherwise, if <a href="index.html#template">template</a> is a function, it - will evaluate <code>template (id, ...)</code>. + will evaluate <code>template (id)</code>. <br/><em>Aliased as <code>uid</code></em>. @@ -5560,10 +6115,6 @@ either a string or a function template to format the ID (<em>optional</em>) </li> - <li><span class="parameter">...</span> - a variable number of arguments to be passed to <a href="index.html#template">template</a>, in case it is a function. - (<em>optional</em>) - </li> </ul> <h3>Returns:</h3> @@ -5696,6 +6247,39 @@ </dd> <dt> + <a name = "flattenPath"></a> + <strong>flattenPath (obj, ...)</strong> + </dt> + <dd> + Flattens object under property path onto provided object. <br/> + It is similar to <a href="index.html#spreadPath">spreadPath</a>, but preserves object under the property path. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">obj</span> + an object + </li> + <li><span class="parameter">...</span> + a property path given as a vararg list + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the passed-in object with changes + </ol> + + + <h3>See also:</h3> + <ul> + <a href="index.html#spreadPath">spreadPath</a> + </ul> + + +</dd> + <dt> <a name = "functions"></a> <strong>functions ([obj])</strong> </dt> @@ -5783,6 +6367,33 @@ </dd> <dt> + <a name = "invert"></a> + <strong>invert (obj)</strong> + </dt> + <dd> + Swaps keys with values. Produces a new object where previous keys are now values, + while previous values are now keys. + <br/><em>Aliased as <code>mirror</code></em> + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">obj</span> + a given object + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + a new object + </ol> + + + + +</dd> + <dt> <a name = "isArray"></a> <strong>isArray (obj)</strong> </dt> @@ -5920,6 +6531,10 @@ </ol> + <h3>See also:</h3> + <ul> + <a href="index.html#allEqual">allEqual</a> + </ul> </dd> @@ -6376,7 +6991,7 @@ </dd> <dt> <a name = "result"></a> - <strong>result (obj, method[, ...])</strong> + <strong>result (obj, method)</strong> </dt> <dd> Invokes an object method. It passes the object itself as the first argument. if <code>method</code> is not @@ -6391,25 +7006,54 @@ <li><span class="parameter">method</span> a string key to index in object <code>obj</code>. </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the returned value of <code>method (obj)</code> call + </ol> + + + + +</dd> + <dt> + <a name = "spreadPath"></a> + <strong>spreadPath (obj, ...)</strong> + </dt> + <dd> + Spreads object under property path onto provided object. <br/> + It is similar to <a href="index.html#flattenPath">flattenPath</a>, but removes object under the property path. + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">obj</span> + an object + </li> <li><span class="parameter">...</span> - Optional args to be passed to <code>method</code> - (<em>optional</em>) + a property path given as a vararg list </li> </ul> <h3>Returns:</h3> <ol> - the returned value of <code>method (obj, ...)</code> call + the passed-in object with changes </ol> + <h3>See also:</h3> + <ul> + <a href="index.html#flattenPath">flattenPath</a> + </ul> </dd> <dt> <a name = "tap"></a> - <strong>tap (obj, f[, ...])</strong> + <strong>tap (obj, f)</strong> </dt> <dd> Invokes interceptor with the object, and then returns object. @@ -6423,11 +7067,7 @@ an object </li> <li><span class="parameter">f</span> - an interceptor function, should be prototyped as <code>f (obj, ...)</code> - </li> - <li><span class="parameter">...</span> - args to be passed to <code>f</code> - (<em>optional</em>) + an interceptor function, should be prototyped as <code>f (obj)</code> </li> </ul> @@ -6528,6 +7168,32 @@ </dd> <dt> + <a name = "type"></a> + <strong>type (obj)</strong> + </dt> + <dd> + Extends Lua's <a href="index.html#type">type</a> function. It returns the type of the given object and also recognises + file userdata + + + <h3>Parameters:</h3> + <ul> + <li><span class="parameter">obj</span> + an object + </li> + </ul> + + <h3>Returns:</h3> + <ol> + + the given object type + </ol> + + + + +</dd> + <dt> <a name = "values"></a> <strong>values (obj)</strong> </dt> @@ -6559,7 +7225,7 @@ </div> <!-- id="main" --> <div id="about"> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> -<i style="float:right;">Last updated 2018-08-23 10:16:23 </i> +<i style="float:right;">Last updated 2018-09-12 11:33:43 </i> </div> <!-- id="about" --> </div> <!-- id="container" --> </body> diff --git a/doc/manual/tutorial.md.html b/doc/manual/tutorial.md.html index 334b0b7..0e1168a 100644 --- a/doc/manual/tutorial.md.html +++ b/doc/manual/tutorial.md.html @@ -105,7 +105,7 @@ M.clear({<span class="number">1</span>,<span class="number">2</span>,<span class </pre> -<h3>each (t, f [, ...])</h3> +<h3>each (t, f)</h3> <p>*Aliases: <code>forEach</code>*.</p> <p>Iterates over each value-key pair in the passed-in table.</p> @@ -148,7 +148,7 @@ M.each(t,<span class="keyword">function</span>(v,i) </pre> -<h3>eachi (t, f [, ...])</h3> +<h3>eachi (t, f)</h3> <p>*Aliases: <code>forEachi</code>*.</p> <p>Iterates only on integer keys in an array table. It returns value-key pairs.</p> @@ -191,9 +191,10 @@ M.at(t,<span class="string">'a'</span>, <span class="string">'ccc'</span>) <span </pre> -<h3>adjust (t, key, f [, ...])</h3> +<h3>adjust (t, key, f)</h3> -<p>Adjusts the value at a given key using a function or a value. In case <code>f</code> is a function, it should be prototyped <code>f(v, ...)</code>. It does not mutate the given table, but rather returns a new array.</p> +<p>Adjusts the value at a given key using a function or a value. In case <code>f</code> is a function, it should be prototyped <code>f(v)</code>. +It does not mutate the given table, but rather returns a new array.</p> <pre> @@ -229,7 +230,7 @@ M.count({<span class="number">1</span>,<span class="number">1</span>,<span class </pre> -<h3>countf (t, f [, ...])</h3> +<h3>countf (t, f)</h3> <p>Counts the number of values passing an iterator test.</p> @@ -245,6 +246,42 @@ M.countf({<span class="global">print</span>, <span class="global">pairs</span>, </pre> +<h3>allEqual (t [, comp])</h3> +<p>*Aliases: <code>alleq</code>*.</p> + +<p>Checks if all values in a collection are equal. Uses <code>M.isEqual</code> by default to compare values.</p> + + +<pre> +M.allEqual({<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>}, comp) <span class="comment">-- => true +</span>M.allEqual({<span class="number">1</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">1</span>,<span class="number">1</span>}, comp) <span class="comment">-- => false +</span> +<span class="keyword">local</span> t1 = {<span class="number">1</span>, <span class="number">2</span>, {<span class="number">3</span>}} +<span class="keyword">local</span> t2 = {<span class="number">1</span>, <span class="number">2</span>, {<span class="number">3</span>}} +M.allEqual({t1, t2}) <span class="comment">-- => true</span> +</pre> + + +<p>Can take an optional <code>comp</code> function which will be used to compare values.</p> + + +<pre> +<span class="keyword">local</span> t1 = {x = <span class="number">1</span>, y = <span class="number">0</span>} +<span class="keyword">local</span> t2 = {x = <span class="number">1</span>, y = <span class="number">0</span>} +<span class="keyword">local</span> t3 = {x = <span class="number">1</span>, y = <span class="number">2</span>} +<span class="keyword">local</span> t4 = {x = <span class="number">1</span>, y = <span class="number">2</span>} +<span class="keyword">local</span> <span class="keyword">function</span> compx(a, b) <span class="keyword">return</span> a.x == b.x <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> compy(a, b) <span class="keyword">return</span> a.y == b.y <span class="keyword">end</span> + +M.allEqual({t1, t2}, compx) <span class="comment">-- => true +</span>M.allEqual({t1, t2}, compy) <span class="comment">-- => true +</span>M.allEqual({t3, t4}, compx) <span class="comment">-- => true +</span>M.allEqual({t3, t4}, compy) <span class="comment">-- => true +</span>M.allEqual({t1, t2, t3, t4}, compx) <span class="comment">-- => true +</span>M.allEqual({t1, t2, t3, t4}, compy) <span class="comment">-- => false</span> +</pre> + + <h3>cycle (t [, n = 1])</h3> <p>*Aliases: <code>loop</code>*.</p> @@ -282,7 +319,7 @@ If <code>n</code> is not provided, it defaults to 1.</p> </pre> -<h3>map (t, f [, ...])</h3> +<h3>map (t, f)</h3> <p>*Aliases: <code>collect</code>*.</p> <p>Executes a function on each value in a given array.</p> @@ -334,7 +371,21 @@ M.reduce({<span class="string">'a'</span>,<span class="string">'b'</span>,<span </pre> -<h3>reduceby (t, f, pred [, state = next(t) [, ...]])</h3> +<h3>best (t, f)</h3> + +<p>Returns the best value passing a selector function. Acts as a special case of <a href="index.html#reduce">reduce</a>, using the first value in <code>t</code> as +an initial state. It thens folds the given table, testing each of its values <code>v</code> and selecting the value passing the +call <code>f(state,v)</code> every time.</p> + + +<pre> +<span class="keyword">local</span> words = {<span class="string">'Lua'</span>, <span class="string">'Programming'</span>, <span class="string">'Language'</span>} +M.best(words, <span class="keyword">function</span>(a,b) <span class="keyword">return</span> #a > #b <span class="keyword">end</span>) <span class="comment">-- => 'Programming' +</span>M.best(words, <span class="keyword">function</span>(a,b) <span class="keyword">return</span> #a < #b <span class="keyword">end</span>) <span class="comment">-- => 'Lua'</span> +</pre> + + +<h3>reduceBy (t, f, pred [, state = next(t)])</h3> <p>Reduces a table considering only values matching a predicate. For example,let us define a set of values.</p> @@ -369,8 +420,8 @@ For example,let us define a set of values.</p> <pre> -M.reduceby(val, add, neg) <span class="comment">-- => -17 -</span>M.reduceby(val, add, pos) <span class="comment">-- => 19</span> +M.reduceBy(val, add, neg) <span class="comment">-- => -17 +</span>M.reduceBy(val, add, pos) <span class="comment">-- => 19</span> </pre> @@ -378,8 +429,8 @@ M.reduceby(val, add, neg) <span class="comment">-- => -17 <pre> -M.reduceby(val, add, neg, <span class="number">17</span>) <span class="comment">-- => 0 -</span>M.reduceby(val, add, pos, -<span class="number">19</span>) <span class="comment">-- => 0</span> +M.reduceBy(val, add, neg, <span class="number">17</span>) <span class="comment">-- => 0 +</span>M.reduceBy(val, add, pos, -<span class="number">19</span>) <span class="comment">-- => 0</span> </pre> @@ -503,7 +554,7 @@ M.findWhere({a, b, c}, {a = <span class="number">3</span>, b = <span class="numb </pre> -<h3>select (t, f [, ...])</h3> +<h3>select (t, f)</h3> <p>*Aliases: <code>filter</code>*.</p> <p>Collects values passing a validation test.</p> @@ -518,7 +569,7 @@ M.<span class="global">select</span>({<span class="number">1</span>,<span class= </pre> -<h3>reject (t, f [, ...])</h3> +<h3>reject (t, f)</h3> <p>*Aliases: <a href="index.html#reject">reject</a>*.</p> <p>Removes all values failing (returning false or nil) a validation test:</p> @@ -533,7 +584,7 @@ M.reject({<span class="number">1</span>,<span class="number">2</span>,<span clas </pre> -<h3>all (t, f [, ...])</h3> +<h3>all (t, f)</h3> <p>*Aliases: <code>every</code>*.</p> <p>Checks whether or not all elements pass a validation test.</p> @@ -545,7 +596,7 @@ M.all({<span class="number">2</span>,<span class="number">4</span>,<span class=" </pre> -<h3>invoke (t, method [, ...])</h3> +<h3>invoke (t, method)</h3> <p>Invokes a given function on each value in a table.</p> @@ -580,7 +631,7 @@ M.pluck(peoples,<span class="string">'age'</span>) <span class="comment">-- => </pre> -<h3>max (t [, transform [, ...]])</h3> +<h3>max (t [, transform])</h3> <p>Returns the maximum value in a collection.</p> @@ -602,7 +653,7 @@ M.max(peoples,<span class="keyword">function</span>(people) <span class="keyword </pre> -<h3>min (t [, transform [, ...]])</h3> +<h3>min (t [, transform])</h3> <p>Returns the minimum value in a collection.</p> @@ -659,6 +710,60 @@ M.sort({<span class="string">'b'</span>,<span class="string">'a'</span>,<span cl </pre> +<h3>sortedk (t [, comp])</h3> + +<p>Iterates on values with respect to key order. Keys are sorted using <code>comp</code> function which defaults to <a href="https://www.lua.org/manual/5.1/manual.html#pdf-math.min">math.min</a>. +It returns upon each call a <code>key, value</code> pair.</p> + + +<pre> +<span class="keyword">local</span> tbl = {}; tbl[<span class="number">3</span>] = <span class="number">5</span> ; tbl[<span class="number">2</span>] = <span class="number">6</span>; tbl[<span class="number">5</span>] = <span class="number">8</span>; tbl[<span class="number">4</span>] = <span class="number">10</span>; tbl[<span class="number">1</span>] = <span class="number">12</span> +<span class="keyword">for</span> k, v <span class="keyword">in</span> M.sortedk(tbl) <span class="keyword">do</span> <span class="global">print</span>(k, v) <span class="keyword">end</span> + +<span class="comment">-- => 1 12 +</span><span class="comment">-- => 2 6 +</span><span class="comment">-- => 3 5 +</span><span class="comment">-- => 4 10 +</span><span class="comment">-- => 5 8 +</span> +<span class="keyword">local</span> <span class="keyword">function</span> comp(a,b) <span class="keyword">return</span> a > b <span class="keyword">end</span> +<span class="keyword">for</span> k, v <span class="keyword">in</span> M.sortedk(tbl, comp) <span class="keyword">do</span> <span class="global">print</span>(k, v) <span class="keyword">end</span> + +<span class="comment">-- => 5 8 +</span><span class="comment">-- => 4 10 +</span><span class="comment">-- => 3 5 +</span><span class="comment">-- => 2 6 +</span><span class="comment">-- => 1 12</span> +</pre> + + +<h3>sortedv (t [, comp])</h3> + +<p>Iterates on values with respect to key order. Keys are sorted using <code>comp</code> function which defaults to <a href="https://www.lua.org/manual/5.1/manual.html#pdf-math.min">math.min</a>. +It returns upon each call a <code>key, value</code> pair.</p> + + +<pre> +<span class="keyword">local</span> tbl = {}; tbl[<span class="number">3</span>] = <span class="number">5</span> ; tbl[<span class="number">2</span>] = <span class="number">6</span>; tbl[<span class="number">5</span>] = <span class="number">8</span>; tbl[<span class="number">4</span>] = <span class="number">10</span>; tbl[<span class="number">1</span>] = <span class="number">12</span> +<span class="keyword">for</span> k, v <span class="keyword">in</span> M.sortedv(tbl) <span class="keyword">do</span> <span class="global">print</span>(k, v) <span class="keyword">end</span> + +<span class="comment">-- => 3 5 +</span><span class="comment">-- => 2 6 +</span><span class="comment">-- => 5 8 +</span><span class="comment">-- => 4 10 +</span><span class="comment">-- => 1 12 +</span> +<span class="keyword">local</span> <span class="keyword">function</span> comp(a,b) <span class="keyword">return</span> a > b <span class="keyword">end</span> +<span class="keyword">for</span> k, v <span class="keyword">in</span> M.sortedv(tbl, comp) <span class="keyword">do</span> <span class="global">print</span>(k, v) <span class="keyword">end</span> + +<span class="comment">-- => 1 12 +</span><span class="comment">-- => 4 10 +</span><span class="comment">-- => 5 8 +</span><span class="comment">-- => 2 6 +</span><span class="comment">-- => 3 5</span> +</pre> + + <h3>sortBy (t [, transform [, comp = math.min]])</h3> <p>Sorts items in a collection based on the result of running a transform function through every item in the collection.</p> @@ -723,7 +828,7 @@ M.each(r, <span class="keyword">function</span>(v) <span class="global">print</s </pre> -<h3>groupBy (t, iter [, ...])</h3> +<h3>groupBy (t, iter)</h3> <p>Groups values in a collection depending on their return value when passed to a predicate test.</p> @@ -739,7 +844,7 @@ M.groupBy({<span class="number">0</span>,<span class="string">'a'</span>,<span c </pre> -<h3>countBy (t [, iter [, ...]])</h3> +<h3>countBy (t, iter)</h3> <p>Splits a table in subsets and provide the count for each subset.</p> @@ -848,6 +953,27 @@ sample = M.sampleProb(array, <span class="number">0.2</span>, <span class="globa </pre> +<h3>nsorted (array [, n = 1[, comp]])</h3> + +<p>Returns the n-top values satisfying a predicate. It takes a comparison function <code>comp</code> used to sort array values, +and then picks the top n-values. It leaves the original array untouched.</p> + + +<pre> +<span class="keyword">local</span> <span class="keyword">function</span> comp(a,b) <span class="keyword">return</span> a > b <span class="keyword">end</span> +M.nsorted(array,<span class="number">5</span>, comp) <span class="comment">-- => {5,4,3,2,1}</span> +</pre> + + +<p><code>n</code> defaults to 1 and <code>comp</code> defaults to the <code><</code> operator.</p> + + +<pre> +<span class="keyword">local</span> array = M.range(<span class="number">1</span>,<span class="number">20</span>) +M.nsorted(array) <span class="comment">-- => {1}</span> +</pre> + + <h3>shuffle (array [, seed])</h3> <p>Shuffles a given array.</p> @@ -859,13 +985,13 @@ sample = M.sampleProb(array, <span class="number">0.2</span>, <span class="globa </pre> -<h3>toArray (...)</h3> +<h3>pack (...)</h3> <p>Converts a vararg list of arguments to an array.</p> <pre> -M.toArray(<span class="number">1</span>,<span class="number">2</span>,<span class="number">8</span>,<span class="string">'d'</span>,<span class="string">'a'</span>,<span class="number">0</span>) <span class="comment">-- => "{1,2,8,'d','a',0}"</span> +M.pack(<span class="number">1</span>,<span class="number">2</span>,<span class="number">8</span>,<span class="string">'d'</span>,<span class="string">'a'</span>,<span class="number">0</span>) <span class="comment">-- => "{1,2,8,'d','a',0}"</span> </pre> @@ -1032,7 +1158,7 @@ M.lastIndexOf({<span class="number">1</span>,<span class="number">2</span>,<span </pre> -<h3>findIndex (array, predicate [, ...])</h3> +<h3>findIndex (array, pred)</h3> <p>Returns the first index at which a predicate passes a truth test.</p> @@ -1044,7 +1170,7 @@ M.findIndex(array, multipleOf3) <span class="comment">-- => 3</span> </pre> -<h3>findLastIndex (array, predicate [, ...])</h3> +<h3>findLastIndex (array, pred)</h3> <p>Returns the last index at which a predicate passes a truthy test.</p> @@ -1143,7 +1269,7 @@ M.removeRange(array, <span class="number">3</span>,<span class="number">8</span> </pre> -<h3>chunk (array, f [, ...])</h3> +<h3>chunk (array, f)</h3> <p>Iterates over an array aggregating consecutive values in subsets tables, on the basis of the return value of <code>f(v, k, ...)</code>. Consecutive elements which return the same value are chunked together.</p> @@ -1190,7 +1316,6 @@ M.initial(array,<span class="number">5</span>) <span class="comment">-- => "{ <h3>last (array [, n = #array])</h3> -<p>*Aliases: <code>skip</code>*.</p> <p>Returns the last N elements in an array.</p> @@ -1277,7 +1402,7 @@ M.union(A,B,C) <span class="comment">-- => "{'a',1,2,3,10}"</span> </pre> -<h3>intersection (array, ...)</h3> +<h3>intersection (...)</h3> <p>Returns the intersection (common-part) of all passed-in arrays:</p> @@ -1286,7 +1411,23 @@ M.union(A,B,C) <span class="comment">-- => "{'a',1,2,3,10}"</span> <span class="keyword">local</span> A = {<span class="string">'a'</span>} <span class="keyword">local</span> B = {<span class="string">'a'</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>} <span class="keyword">local</span> C = {<span class="number">2</span>,<span class="number">10</span>,<span class="number">1</span>,<span class="string">'a'</span>} -M.intersection(A,B,C) <span class="comment">-- => "{'a',2,1}"</span> +M.intersection(A,B,C) <span class="comment">-- => "{'a'}"</span> +</pre> + + +<h3>disjoint (...)</h3> + +<p>Checks if all passed in arrays are disjoint.</p> + + +<pre> +<span class="keyword">local</span> A = {<span class="string">'a'</span>} +<span class="keyword">local</span> B = {<span class="string">'a'</span>,<span class="number">1</span>,<span class="number">3</span>} +<span class="keyword">local</span> C = {<span class="number">3</span>,<span class="number">10</span>,<span class="number">2</span>} + +M.disjoint(A,B) <span class="comment">-- => false +</span>M.disjoint(A,C) <span class="comment">-- => true +</span>M.disjoint(B,C) <span class="comment">-- => false</span> </pre> @@ -1326,6 +1467,16 @@ M.isunique({<span class="number">1</span>,<span class="number">2</span>,<span cl </pre> +<h3>duplicates (array)</h3> + +<p>Returns an array list of all duplicates in array.</p> + + +<pre> +M.duplicates({<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="number">8</span>,<span class="number">8</span>,<span class="number">3</span>,<span class="number">2</span>,<span class="number">4</span>}) <span class="comment">-- => {2,3,8}</span> +</pre> + + <h3>zip (...)</h3> <p>*Aliases: <code>transpose</code>*.</p> @@ -1595,17 +1746,6 @@ t = {<span class="string">'a'</span>,<span class="string">'b'</span>,<span class </pre> -<h3>invert (array)</h3> -<p>*Aliases: <code>mirror</code>*.</p> - -<p>Switches <tt>key-value</tt> pairs:</p> - - -<pre> -M.invert {<span class="string">'a'</span>,<span class="string">'b'</span>,<span class="string">'c'</span>} <span class="comment">-- => "{a=1, b=2, c=3}"</span> -</pre> - - <h3>concat (array [, sep = '' [, i = 1 [, j = #array]]])</h3> <p>*Aliases: <code>join</code>*.</p> @@ -1628,6 +1768,28 @@ M.concat({<span class="string">'a'</span>,<span class="number">1</span>,<span cl </pre> +<h3>xpairs (value, array)</h3> + +<p>Creates pairs from value and array. Value is always prepended to the pair.</p> + + +<pre> +<span class="keyword">local</span> t = M.xpairs(<span class="number">1</span>, {<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}) +<span class="comment">-- => {{1,1},{1,2},{1,3}}</span> +</pre> + + +<h3>xpairsRight (value, array)</h3> + +<p>Creates pairs from value and array. Value is always appended as the last item to the pair.</p> + + +<pre> +<span class="keyword">local</span> t = M.xpairsRight(<span class="number">1</span>, {<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}) +<span class="comment">-- => {{1,1},{2,1},{3,1}}</span> +</pre> + + <h3>sum (array)</h3> <p>Returns the sum of array values.</p> @@ -1697,6 +1859,18 @@ M.identity(<span class="number">1</span>)<span class="comment">-- => 1 </pre> +<h3>call (f [, ...])</h3> + +<p>Calls <code>f</code> with the supplied arguments. Returns the results of <code>f(...)</code>.</p> + + +<pre> +M.call(<span class="global">math</span>.pow, <span class="number">2</span>, <span class="number">3</span>) <span class="comment">-- => 8 +</span>M.call(<span class="global">string</span>.len, <span class="string">'hello'</span> ) <span class="comment">-- => 5 +</span>M.call(<span class="global">table</span>.concat, {<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>}, <span class="string">','</span>, <span class="number">2</span>, <span class="number">4</span>) <span class="comment">-- => {2,3,4}</span> +</pre> + + <h3>constant (value)</h3> <p>Creates a constant function. This function will continuously yield the same output.</p> @@ -1712,7 +1886,8 @@ pi(<span class="number">1</span>) <span class="comment">-- => 3.1415926535898 <h3>applySpec (specs)</h3> -<p>Returns a function which applies <code>specs</code> on args. This function will produce an object having the same structure than <code>specs</code> by mapping each property to the result of calling its associated function with the supplied arguments.</p> +<p>Returns a function which applies <code>specs</code> on args. This function will produce an object having the same structure than <code>specs</code> +by mapping each property to the result of calling its associated function with the supplied arguments.</p> <pre> @@ -1725,6 +1900,68 @@ stats(<span class="number">5</span>,<span class="number">4</span>,<span class="n </pre> +<h3>thread (value [, ...])</h3> + +<p>Threads <a href="index.html#obj:value">value</a> through a series of functions.</p> + + +<pre> +<span class="keyword">local</span> <span class="keyword">function</span> inc(x) <span class="keyword">return</span> x + <span class="number">1</span> <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> double(x) <span class="keyword">return</span> <span class="number">2</span> * x <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> square(x) <span class="keyword">return</span> x * x <span class="keyword">end</span> +M.thread(<span class="number">2</span>, inc, double, square) <span class="comment">-- => 36 +</span>M.thread(<span class="number">3</span>, double, inc, square) <span class="comment">-- => 49 +</span>M.thread(<span class="number">4</span>, square, double, inc) <span class="comment">-- => 33 +</span>M.thread(<span class="number">5</span>, square, inc, double) <span class="comment">-- => 52</span> +</pre> + + +<p>If a function expects more than one args, it can be specified using an array list, +where the first item is the function and the following are the remaining args neeeded. </p> + + +<pre> +<span class="keyword">local</span> <span class="keyword">function</span> inc(x) <span class="keyword">return</span> x + <span class="number">1</span> <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> add(x, y) <span class="keyword">return</span> x * y <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> pow(x, y) <span class="keyword">return</span> x ^ y <span class="keyword">end</span> +M.thread(<span class="number">2</span>, inc, {add, <span class="number">3</span>}, {pow, <span class="number">2</span>}) <span class="comment">-- => 36 +</span>M.thread(<span class="number">2</span>, {add, <span class="number">4</span>}, inc, {pow, <span class="number">2</span>}) <span class="comment">-- => 49</span> +</pre> + + +<h3>threadRight (value [, ...])</h3> + +<p>Threads <a href="index.html#obj:value">value</a> through a series of functions. If a function expects more than one args, +it can be specified using an array list, where the first item is the function and the following are +the remaining args neeeded. The value is used as the last input.</p> + + +<pre> +<span class="keyword">local</span> <span class="keyword">function</span> inc(x) <span class="keyword">return</span> x + <span class="number">1</span> <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> add(x, y) <span class="keyword">return</span> x * y <span class="keyword">end</span> +<span class="keyword">local</span> <span class="keyword">function</span> pow(x, y) <span class="keyword">return</span> x ^ y <span class="keyword">end</span> +M.threadRight(<span class="number">2</span>, inc, {add, <span class="number">3</span>}, {pow, <span class="number">2</span>}) <span class="comment">-- => 64 +</span>M.threadRight(<span class="number">2</span>, {add, <span class="number">4</span>}, inc, {pow, <span class="number">2</span>}) <span class="comment">-- => 128</span> +</pre> + + +<h3>dispatch (...)</h3> + +<p>Returns a dispatching function. When called with arguments, this function invokes each of its functions +in the passed-in order and returns the results of the first non-nil evaluation.</p> + + +<pre> +<span class="keyword">local</span> f = M.dispatch( + <span class="keyword">function</span>() <span class="keyword">return</span> <span class="keyword">nil</span> <span class="keyword">end</span>, + <span class="keyword">function</span> (v) <span class="keyword">return</span> v+<span class="number">1</span> <span class="keyword">end</span>, + <span class="keyword">function</span> (v) <span class="keyword">return</span> <span class="number">2</span>*v <span class="keyword">end</span> +) +f(<span class="number">5</span>) <span class="comment">-- => 6 +</span>f(<span class="number">7</span>) <span class="comment">-- => 8</span> +</pre> + + <h3>memoize (f)</h3> <p>*Aliases: <code>cache</code>*.</p> @@ -1869,7 +2106,7 @@ greet_backwards(<span class="string">'John'</span>) </pre> -<h3>times (iter [, n [, ...]])</h3> +<h3>times (iter [, n])</h3> <p>Calls a given function <code>n</code> times.</p> @@ -1962,7 +2199,58 @@ window.setName(<span class="string">'fooApp'</span>) </pre> -<h3>uniqueId ([template [, ...]])</h3> +<h3>both (...)</h3> + +<p>Returns a validation function. Given a set of functions, the validation function +evaluates to <code>true</code> only when all its funcs returns <code>true</code>.</p> + + +<pre> +<span class="keyword">local</span> f = M.both( + <span class="keyword">function</span>(x) <span class="keyword">return</span> x > <span class="number">0</span> <span class="keyword">end</span>, + <span class="keyword">function</span>(x) <span class="keyword">return</span> x < <span class="number">10</span> <span class="keyword">end</span>, + <span class="keyword">function</span>(x) <span class="keyword">return</span> x % <span class="number">2</span> == <span class="number">0</span> <span class="keyword">end</span> +) +f(<span class="number">2</span>) <span class="comment">-- => true +</span>f(<span class="number">8</span>) <span class="comment">-- => true +</span>f(<span class="number">9</span>) <span class="comment">-- => false</span> +</pre> + + +<h3>either (...)</h3> + +<p>Returns a validation function. Given a set of functions, the validation function +evaluates to <code>true</code> when one of its funcs returns <code>true</code>.</p> + + +<pre> +<span class="keyword">local</span> f = M.either( + <span class="keyword">function</span>(x) <span class="keyword">return</span> x > <span class="number">0</span> <span class="keyword">end</span>, + <span class="keyword">function</span>(x) <span class="keyword">return</span> x % <span class="number">2</span> == <span class="number">0</span> <span class="keyword">end</span> +) +f(<span class="number">0</span>) <span class="comment">-- => true +</span>f(-<span class="number">3</span>) <span class="comment">-- => false</span> +</pre> + + +<h3>neither (...)</h3> + +<p>Returns a validation function. Given a set of functions, the validation function +evaluates to <code>true</code> when neither of its funcs returns <code>true</code>.</p> + + +<pre> +<span class="keyword">local</span> f = M.neither( + <span class="keyword">function</span>(x) <span class="keyword">return</span> x > <span class="number">10</span> <span class="keyword">end</span>, + <span class="keyword">function</span>(x) <span class="keyword">return</span> x % <span class="number">2</span> == <span class="number">0</span> <span class="keyword">end</span> +) +f(<span class="number">12</span>) <span class="comment">-- => false +</span>f(<span class="number">8</span>) <span class="comment">-- => false +</span>f(<span class="number">7</span>) <span class="comment">-- => true</span> +</pre> + + +<h3>uniqueId ([template])</h3> <p>*Aliases: <code>uid</code>*.</p> <p>Returns an unique integer ID.</p> @@ -2019,8 +2307,31 @@ iter_po2() <span class="comment">-- => 2 </pre> -<h3>array (...)</h3> -<p>*Aliases: <code>tabulate</code>*.</p> +<h3>skip (iter [, n = 1])</h3> + +<p>Consumes the first <code>n</code> values of a iterator then returns it.</p> + + +<pre> +<span class="keyword">local</span> w = <span class="string">"hello"</span> +<span class="keyword">local</span> char = <span class="global">string</span>.gmatch(w,<span class="string">'.'</span>) +<span class="keyword">local</span> iter = M.skip(char, <span class="number">3</span>) +<span class="keyword">for</span> w <span class="keyword">in</span> iter <span class="keyword">do</span> <span class="global">print</span>(w) <span class="keyword">end</span> <span class="comment">-- => 'l', 'o'</span> +</pre> + + +<p><code>n</code> defaults to 1 when not given.</p> + + +<pre> +<span class="keyword">local</span> w = <span class="string">"hello"</span> +<span class="keyword">local</span> char = <span class="global">string</span>.gmatch(w,<span class="string">'.'</span>) +<span class="keyword">local</span> iter = M.skip(char) +<span class="keyword">for</span> w <span class="keyword">in</span> iter <span class="keyword">do</span> <span class="global">print</span>(w) <span class="keyword">end</span> <span class="comment">-- => 'e', 'l', 'l', 'o'</span> +</pre> + + +<h3>tabulate (...)</h3> <p>Iterates a given iterator function and returns its values packed in an array.</p> @@ -2028,7 +2339,30 @@ iter_po2() <span class="comment">-- => 2 <pre> <span class="keyword">local</span> text = <span class="string">'letters'</span> <span class="keyword">local</span> chars = <span class="global">string</span>.gmatch(text, <span class="string">'.'</span>) -<span class="keyword">local</span> letters = M.array(chars) <span class="comment">-- => {'l','e','t','t','e','r','s'}</span> +M.tabulate(chars) <span class="comment">-- => {'l','e','t','t','e','r','s'}</span> +</pre> + + +<h3>iterlen (...)</h3> + +<p>Returns the length of an iterator.</p> + + +<pre> +<span class="keyword">local</span> text = <span class="string">'letters'</span> +<span class="keyword">local</span> chars = <span class="global">string</span>.gmatch(text, <span class="string">'.'</span>) +M.iterlen(chars) <span class="comment">-- => 7</span> +</pre> + + +<p>It consumes the iterator itself.</p> + + +<pre> +<span class="keyword">local</span> text = <span class="string">'lua'</span> +<span class="keyword">local</span> chars = <span class="global">string</span>.gmatch(text, <span class="string">'.'</span>) +M.iterlen(chars) <span class="comment">-- => 3 +</span>chars() <span class="comment">-- => nil</span> </pre> @@ -2118,6 +2452,18 @@ f(<span class="string">'a'</span>,<span class="string">'b'</span>,<span class="s </pre> +<h3>noarg (f)</h3> + +<p>Returns a function with an arity of 0. The new function ignores any arguments passed to it.</p> + + +<pre> +<span class="keyword">local</span> f = M.noarg(<span class="keyword">function</span> (x) <span class="keyword">return</span> x <span class="keyword">or</span> <span class="string">'default'</span> <span class="keyword">end</span>) +f(<span class="number">1</span>) <span class="comment">-- => 'default' +</span>f(<span class="keyword">function</span>() <span class="keyword">end</span>, <span class="number">3</span>) <span class="comment">-- => 'default'</span> +</pre> + + <h3>rearg (f, indexes)</h3> <p>Returns a function which runs with arguments arranged according to given <code>indexes</code>.</p> @@ -2391,6 +2737,30 @@ M.path(entity,<span class="string">'pos'</span>,<span class="string">'x'</span>) </pre> +<h3>spreadPath (obj, ...)</h3> + +<p>Spreads object under property path onto provided object. It is similar to <a href="index.html#flattenPath">flattenPath</a>, but removes object under the property path.</p> + + +<pre> +<span class="keyword">local</span> obj = {a = <span class="number">1</span>, b = <span class="number">2</span>, c = {d = <span class="number">3</span>, e = <span class="number">4</span>, f = {g = <span class="number">5</span>}}} +M.spreadPath(obj, <span class="string">'c'</span>, <span class="string">'f'</span>) +<span class="comment">-- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {f = {}}}</span> +</pre> + + +<h3>flattenPath (obj, ...)</h3> + +<p>Flattens object under property path onto provided object. It is similar to <a href="index.html#spreadPath">spreadPath</a>, but preserves object under the property path.</p> + + +<pre> +<span class="keyword">local</span> obj = {a = <span class="number">1</span>, b = <span class="number">2</span>, c = {d = <span class="number">3</span>, e = <span class="number">4</span>, f = {g = <span class="number">5</span>}}} +M.spreadPath(obj, <span class="string">'c'</span>, <span class="string">'f'</span>) +<span class="comment">-- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {d = 3, e = 4, f = {g = 5}}}</span> +</pre> + + <h3>kvpairs (obj)</h3> <p>Converts an object to an array-list of key-value pairs.</p> @@ -2421,6 +2791,18 @@ obj = M.toObj(list_pairs) </pre> +<h3>invert (obj)</h3> +<p>*Aliases: <code>mirror</code>*.</p> + +<p>Switches <tt>key-value</tt> pairs:</p> + + +<pre> +M.invert {<span class="string">'a'</span>,<span class="string">'b'</span>,<span class="string">'c'</span>} <span class="comment">-- => "{a=1, b=2, c=3}" +</span>M.invert {x = <span class="number">1</span>, y = <span class="number">2</span>} <span class="comment">-- => "{'x','y'}"</span> +</pre> + + <h3>property (key)</h3> <p>Returns a function that will return the key property of any passed-in object.</p> @@ -2504,7 +2886,7 @@ M.functions(t, <span class="keyword">true</span>) <span class="comment">-- => </pre> -<h3>tap (obj, f [, ...])</h3> +<h3>tap (obj, f)</h3> <p>Invokes a given interceptor function on some object, and then returns the object itself. Useful to tap into method chaining to hook intermediate results. The passed-in interceptor should be prototyped as <code>f(obj,...)</code>.</p> @@ -2581,7 +2963,7 @@ M.isEqual(<span class="number">1</span>,<span class="number">1</span>) <span cla </pre> -<h3>result (obj, method [, ...])</h3> +<h3>result (obj, method)</h3> <p>Calls an object method, passing it as a first argument the object itself.</p> @@ -2642,6 +3024,19 @@ M.isIterable({}) <span class="comment">-- => true </pre> +<h3>type (obj)</h3> + +<p>Extends Lua's <a href="index.html#type">type</a> function. It returns the type of the given object and also recognises 'file' userdata</p> + + +<pre> +M.<span class="global">type</span>(<span class="string">'string'</span>) <span class="comment">-- => 'string' +</span>M.<span class="global">type</span>(<span class="global">table</span>) <span class="comment">-- => 'table' +</span>M.<span class="global">type</span>(<span class="keyword">function</span>() <span class="keyword">end</span>) <span class="comment">-- => 'function' +</span>M.<span class="global">type</span>(<span class="global">io</span>.open(<span class="string">'f'</span>,<span class="string">'w'</span>)) <span class="comment">-- => 'file'</span> +</pre> + + <h3>isEmpty ([obj])</h3> <p>Is the given argument empty ?</p> @@ -2862,7 +3257,7 @@ M.import(context, <span class="keyword">true</span>) </div> <!-- id="main" --> <div id="about"> <i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i> -<i style="float:right;">Last updated 2018-08-23 10:16:23 </i> +<i style="float:right;">Last updated 2018-09-12 11:33:43 </i> </div> <!-- id="about" --> </div> <!-- id="container" --> </body> diff --git a/doc/tutorial.md b/doc/tutorial.md index 9636094..4c7dfeb 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -43,7 +43,7 @@ Clears a table. All its values becomes nil. Returns the passed-in table. M.clear({1,2,'hello',true}) -- => {} ```` -### each (t, f [, ...]) +### each (t, f) *Aliases: `forEach`*. Iterates over each value-key pair in the passed-in table. @@ -80,7 +80,7 @@ end) -- => cc ```` -### eachi (t, f [, ...]) +### eachi (t, f) *Aliases: `forEachi`*. Iterates only on integer keys in an array table. It returns value-key pairs. @@ -117,9 +117,10 @@ local t = {a = 4, bb = true, ccc = false} M.at(t,'a', 'ccc') -- => "{4, false}" ```` -### adjust (t, key, f [, ...]) +### adjust (t, key, f) -Adjusts the value at a given key using a function or a value. In case `f` is a function, it should be prototyped `f(v, ...)`. It does not mutate the given table, but rather returns a new array. +Adjusts the value at a given key using a function or a value. In case `f` is a function, it should be prototyped `f(v)`. +It does not mutate the given table, but rather returns a new array. ```lua local t = {1,2,3} @@ -149,7 +150,7 @@ Returns the size of the list in case no value was provided. M.count({1,1,2,3,3}) -- => 5 ```` -### countf (t, f [, ...]) +### countf (t, f) Counts the number of values passing an iterator test. @@ -163,6 +164,38 @@ M.countf({print, pairs, os, assert, ipairs}, function(v) end) -- => 4 ```` +### allEqual (t [, comp]) +*Aliases: `alleq`*. + +Checks if all values in a collection are equal. Uses `M.isEqual` by default to compare values. + +```lua +M.allEqual({1,1,1,1,1}, comp) -- => true +M.allEqual({1,1,2,1,1}, comp) -- => false + +local t1 = {1, 2, {3}} +local t2 = {1, 2, {3}} +M.allEqual({t1, t2}) -- => true +```` + +Can take an optional `comp` function which will be used to compare values. + +```lua +local t1 = {x = 1, y = 0} +local t2 = {x = 1, y = 0} +local t3 = {x = 1, y = 2} +local t4 = {x = 1, y = 2} +local function compx(a, b) return a.x == b.x end +local function compy(a, b) return a.y == b.y end + +M.allEqual({t1, t2}, compx) -- => true +M.allEqual({t1, t2}, compy) -- => true +M.allEqual({t3, t4}, compx) -- => true +M.allEqual({t3, t4}, compy) -- => true +M.allEqual({t1, t2, t3, t4}, compx) -- => true +M.allEqual({t1, t2, t3, t4}, compy) -- => false +```` + ### cycle (t [, n = 1]) *Aliases: `loop`*. @@ -196,7 +229,7 @@ end -- => 3 ```` -### map (t, f [, ...]) +### map (t, f) *Aliases: `collect`*. Executes a function on each value in a given array. @@ -238,7 +271,19 @@ local function concat(a,b) return a..b end M.reduce({'a','b','c','d'},concat) -- => abcd ```` -### reduceby (t, f, pred [, state = next(t) [, ...]]) +### best (t, f) + +Returns the best value passing a selector function. Acts as a special case of `reduce`, using the first value in `t` as +an initial state. It thens folds the given table, testing each of its values `v` and selecting the value passing the +call `f(state,v)` every time. + +```lua +local words = {'Lua', 'Programming', 'Language'} +M.best(words, function(a,b) return #a > #b end) -- => 'Programming' +M.best(words, function(a,b) return #a < #b end) -- => 'Lua' +```` + +### reduceBy (t, f, pred [, state = next(t)]) Reduces a table considering only values matching a predicate. For example,let us define a set of values. @@ -266,15 +311,15 @@ local function pos(v) return v>=0 end Then we can perform reduction considering only negative or positive values : ```lua -M.reduceby(val, add, neg) -- => -17 -M.reduceby(val, add, pos) -- => 19 +M.reduceBy(val, add, neg) -- => -17 +M.reduceBy(val, add, pos) -- => 19 ```` An initial state can be passed in. ```lua -M.reduceby(val, add, neg, 17) -- => 0 -M.reduceby(val, add, pos, -19) -- => 0 +M.reduceBy(val, add, neg, 17) -- => 0 +M.reduceBy(val, add, pos, -19) -- => 0 ```` ### reduceRight (t, f [, state = next(t)]) @@ -379,7 +424,7 @@ local c = {a = 3, b = 4, e = 5} M.findWhere({a, b, c}, {a = 3, b = 4}) == c -- => true ```` -### select (t, f [, ...]) +### select (t, f) *Aliases: `filter`*. Collects values passing a validation test. @@ -392,7 +437,7 @@ M.select({1,2,3,4,5,6,7}, isEven) -- => "{2,4,6}" M.select({1,2,3,4,5,6,7}, isOdd) -- => "{1,3,5,7}" ```` -### reject (t, f [, ...]) +### reject (t, f) *Aliases: `reject`*. Removes all values failing (returning false or nil) a validation test: @@ -405,7 +450,7 @@ M.reject({1,2,3,4,5,6,7}, isEven) -- => "{1,3,5,7}" M.reject({1,2,3,4,5,6,7}, isOdd) -- => "{2,4,6}" ```` -### all (t, f [, ...]) +### all (t, f) *Aliases: `every`*. Checks whether or not all elements pass a validation test. @@ -415,7 +460,7 @@ local function isEven(v) return v%2==0 end M.all({2,4,6}, isEven) -- => true ```` -### invoke (t, method [, ...]) +### invoke (t, method) Invokes a given function on each value in a table. @@ -444,7 +489,7 @@ M.pluck(peoples,'age') -- => "{23,17,15,33}" M.pluck(peoples,'name') -- => "{'John', 'Peter', 'Steve'}" ```` -### max (t [, transform [, ...]]) +### max (t [, transform]) Returns the maximum value in a collection. @@ -462,7 +507,7 @@ local peoples = { M.max(peoples,function(people) return people.age end) -- => 33 ```` -### min (t [, transform [, ...]]) +### min (t [, transform]) Returns the minimum value in a collection. @@ -509,6 +554,56 @@ M.sort({'b','a','d','c'}, function(a,b) end) -- => "{'d','c','b','a'}" ```` +### sortedk (t [, comp]) + +Iterates on values with respect to key order. Keys are sorted using `comp` function which defaults to `math.min`. +It returns upon each call a `key, value` pair. + +```lua +local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 +for k, v in M.sortedk(tbl) do print(k, v) end + +-- => 1 12 +-- => 2 6 +-- => 3 5 +-- => 4 10 +-- => 5 8 + +local function comp(a,b) return a > b end +for k, v in M.sortedk(tbl, comp) do print(k, v) end + +-- => 5 8 +-- => 4 10 +-- => 3 5 +-- => 2 6 +-- => 1 12 +```` + +### sortedv (t [, comp]) + +Iterates on values with respect to key order. Keys are sorted using `comp` function which defaults to `math.min`. +It returns upon each call a `key, value` pair. + +```lua +local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 +for k, v in M.sortedv(tbl) do print(k, v) end + +-- => 3 5 +-- => 2 6 +-- => 5 8 +-- => 4 10 +-- => 1 12 + +local function comp(a,b) return a > b end +for k, v in M.sortedv(tbl, comp) do print(k, v) end + +-- => 1 12 +-- => 4 10 +-- => 5 8 +-- => 2 6 +-- => 3 5 +```` + ### sortBy (t [, transform [, comp = math.min]]) Sorts items in a collection based on the result of running a transform function through every item in the collection. @@ -565,7 +660,7 @@ print(table.concat(r,',')) -- => {1,2,3,4,5} ```` -### groupBy (t, iter [, ...]) +### groupBy (t, iter) Groups values in a collection depending on their return value when passed to a predicate test. @@ -579,7 +674,7 @@ M.groupBy({0,'a',true, false,nil,b,0.5},type) -- => "{number = {0,0.5}, string = {'a'}, boolean = {true, false}}" ```` -### countBy (t [, iter [, ...]]) +### countBy (t, iter) Splits a table in subsets and provide the count for each subset. @@ -671,6 +766,23 @@ print(table.concat(sample,',')) -- => 1,6,10,12,15,20 (or similar) ```` +### nsorted (array [, n = 1[, comp]]) + +Returns the n-top values satisfying a predicate. It takes a comparison function `comp` used to sort array values, +and then picks the top n-values. It leaves the original array untouched. + +```lua +local function comp(a,b) return a > b end +M.nsorted(array,5, comp) -- => {5,4,3,2,1} +```` + +`n` defaults to 1 and `comp` defaults to the `<` operator. + +```lua +local array = M.range(1,20) +M.nsorted(array) -- => {1} +```` + ### shuffle (array [, seed]) Shuffles a given array. @@ -680,12 +792,12 @@ local list = M.shuffle {1,2,3,4,5,6} -- => "{3,2,6,4,1,5}" M.each(list,print) ```` -### toArray (...) +### pack (...) Converts a vararg list of arguments to an array. ```lua -M.toArray(1,2,8,'d','a',0) -- => "{1,2,8,'d','a',0}" +M.pack(1,2,8,'d','a',0) -- => "{1,2,8,'d','a',0}" ```` ### find (array, value [, from = 1]) @@ -819,7 +931,7 @@ Returns the index of the last occurence of a given value in an array. M.lastIndexOf({1,2,2,3},2) -- => 3 ```` -### findIndex (array, predicate [, ...]) +### findIndex (array, pred) Returns the first index at which a predicate passes a truth test. @@ -829,7 +941,7 @@ local function multipleOf3(v) return v%3==0 end M.findIndex(array, multipleOf3) -- => 3 ```` -### findLastIndex (array, predicate [, ...]) +### findLastIndex (array, pred) Returns the last index at which a predicate passes a truthy test. @@ -910,7 +1022,7 @@ local array = {1,2,3,4,5,6,7,8,9} M.removeRange(array, 3,8) -- => "{1,2,9}" ```` -### chunk (array, f [, ...]) +### chunk (array, f) Iterates over an array aggregating consecutive values in subsets tables, on the basis of the return value of `f(v, k, ...)`. Consecutive elements which return the same value are chunked together. @@ -949,7 +1061,6 @@ M.initial(array,5) -- => "{1,2,3,4}" ```` ### last (array [, n = #array]) -*Aliases: `skip`*. Returns the last N elements in an array. @@ -1020,7 +1131,7 @@ local C = {2,10} M.union(A,B,C) -- => "{'a',1,2,3,10}" ```` -### intersection (array, ...) +### intersection (...) Returns the intersection (common-part) of all passed-in arrays: @@ -1028,7 +1139,21 @@ Returns the intersection (common-part) of all passed-in arrays: local A = {'a'} local B = {'a',1,2,3} local C = {2,10,1,'a'} -M.intersection(A,B,C) -- => "{'a',2,1}" +M.intersection(A,B,C) -- => "{'a'}" +```` + +### disjoint (...) + +Checks if all passed in arrays are disjoint. + +```lua +local A = {'a'} +local B = {'a',1,3} +local C = {3,10,2} + +M.disjoint(A,B) -- => false +M.disjoint(A,C) -- => true +M.disjoint(B,C) -- => false ```` ### symmetricDifference (array, array2) @@ -1061,6 +1186,14 @@ M.isunique({1,2,3,4,5}) -- => true M.isunique({1,2,3,4,4}) -- => false ```` +### duplicates (array) + +Returns an array list of all duplicates in array. + +```lua +M.duplicates({1,2,3,3,8,8,3,2,4}) -- => {2,3,8} +```` + ### zip (...) *Aliases: `transpose`*. @@ -1294,15 +1427,6 @@ end -- => 'abc' ```` -### invert (array) -*Aliases: `mirror`*. - -Switches <tt>key-value</tt> pairs: - -```lua -M.invert {'a','b','c'} -- => "{a=1, b=2, c=3}" -```` - ### concat (array [, sep = '' [, i = 1 [, j = #array]]]) *Aliases: `join`*. @@ -1321,6 +1445,24 @@ local t = M.xprod({1,2},{'a','b'}) -- => {{1,'a'},{1,'b'},{2,'a'},{2,'b'}} ```` +### xpairs (value, array) + +Creates pairs from value and array. Value is always prepended to the pair. + +```lua +local t = M.xpairs(1, {1, 2, 3}) +-- => {{1,1},{1,2},{1,3}} +```` + +### xpairsRight (value, array) + +Creates pairs from value and array. Value is always appended as the last item to the pair. + +```lua +local t = M.xpairsRight(1, {1, 2, 3}) +-- => {{1,1},{2,1},{3,1}} +```` + ### sum (array) Returns the sum of array values. @@ -1377,6 +1519,16 @@ M.identity(false) -- => false M.identity('hello!') -- => 'hello!' ```` +### call (f [, ...]) + +Calls `f` with the supplied arguments. Returns the results of `f(...)`. + +```lua +M.call(math.pow, 2, 3) -- => 8 +M.call(string.len, 'hello' ) -- => 5 +M.call(table.concat, {1,2,3,4,5}, ',', 2, 4) -- => {2,3,4} +```` + ### constant (value) Creates a constant function. This function will continuously yield the same output. @@ -1390,7 +1542,8 @@ pi(math.pi) -- => 3.1415926535898 ### applySpec (specs) -Returns a function which applies `specs` on args. This function will produce an object having the same structure than `specs` by mapping each property to the result of calling its associated function with the supplied arguments. +Returns a function which applies `specs` on args. This function will produce an object having the same structure than `specs` +by mapping each property to the result of calling its associated function with the supplied arguments. ```lua local stats = M.applySpec({ @@ -1401,6 +1554,60 @@ local stats = M.applySpec({ stats(5,4,10,1,8) -- => {min = 1, max = 10} ```` +### thread (value [, ...]) + +Threads `value` through a series of functions. + +```lua +local function inc(x) return x + 1 end +local function double(x) return 2 * x end +local function square(x) return x * x end +M.thread(2, inc, double, square) -- => 36 +M.thread(3, double, inc, square) -- => 49 +M.thread(4, square, double, inc) -- => 33 +M.thread(5, square, inc, double) -- => 52 +```` + +If a function expects more than one args, it can be specified using an array list, +where the first item is the function and the following are the remaining args neeeded. + +```lua +local function inc(x) return x + 1 end +local function add(x, y) return x * y end +local function pow(x, y) return x ^ y end +M.thread(2, inc, {add, 3}, {pow, 2}) -- => 36 +M.thread(2, {add, 4}, inc, {pow, 2}) -- => 49 +```` + +### threadRight (value [, ...]) + +Threads `value` through a series of functions. If a function expects more than one args, +it can be specified using an array list, where the first item is the function and the following are +the remaining args neeeded. The value is used as the last input. + +```lua +local function inc(x) return x + 1 end +local function add(x, y) return x * y end +local function pow(x, y) return x ^ y end +M.threadRight(2, inc, {add, 3}, {pow, 2}) -- => 64 +M.threadRight(2, {add, 4}, inc, {pow, 2}) -- => 128 +```` + +### dispatch (...) + +Returns a dispatching function. When called with arguments, this function invokes each of its functions +in the passed-in order and returns the results of the first non-nil evaluation. + +```lua +local f = M.dispatch( + function() return nil end, + function (v) return v+1 end, + function (v) return 2*v end +) +f(5) -- => 6 +f(7) -- => 8 +```` + ### memoize (f) *Aliases: `cache`*. @@ -1525,7 +1732,7 @@ greet_backwards('John') -- => hi: nhoJ ```` -### times (iter [, n [, ...]]) +### times (iter [, n]) Calls a given function `n` times. @@ -1606,7 +1813,52 @@ end -- => 20 is multiple of 2 ```` -### uniqueId ([template [, ...]]) +### both (...) + +Returns a validation function. Given a set of functions, the validation function +evaluates to `true` only when all its funcs returns `true`. + +```lua +local f = M.both( + function(x) return x > 0 end, + function(x) return x < 10 end, + function(x) return x % 2 == 0 end +) +f(2) -- => true +f(8) -- => true +f(9) -- => false +```` + +### either (...) + +Returns a validation function. Given a set of functions, the validation function +evaluates to `true` when one of its funcs returns `true`. + +```lua +local f = M.either( + function(x) return x > 0 end, + function(x) return x % 2 == 0 end +) +f(0) -- => true +f(-3) -- => false +```` + +### neither (...) + +Returns a validation function. Given a set of functions, the validation function +evaluates to `true` when neither of its funcs returns `true`. + +```lua +local f = M.neither( + function(x) return x > 10 end, + function(x) return x % 2 == 0 end +) +f(12) -- => false +f(8) -- => false +f(7) -- => true +```` + +### uniqueId ([template]) *Aliases: `uid`*. Returns an unique integer ID. @@ -1653,15 +1905,53 @@ iter_po2() -- => 8 iter_po2() -- => nil ```` -### array (...) -*Aliases: `tabulate`*. +### skip (iter [, n = 1]) + +Consumes the first `n` values of a iterator then returns it. + +```lua +local w = "hello" +local char = string.gmatch(w,'.') +local iter = M.skip(char, 3) +for w in iter do print(w) end -- => 'l', 'o' +```` + +`n` defaults to 1 when not given. + +```lua +local w = "hello" +local char = string.gmatch(w,'.') +local iter = M.skip(char) +for w in iter do print(w) end -- => 'e', 'l', 'l', 'o' +```` + +### tabulate (...) Iterates a given iterator function and returns its values packed in an array. ```lua local text = 'letters' local chars = string.gmatch(text, '.') -local letters = M.array(chars) -- => {'l','e','t','t','e','r','s'} +M.tabulate(chars) -- => {'l','e','t','t','e','r','s'} +```` + +### iterlen (...) + +Returns the length of an iterator. + +```lua +local text = 'letters' +local chars = string.gmatch(text, '.') +M.iterlen(chars) -- => 7 +```` + +It consumes the iterator itself. + +```lua +local text = 'lua' +local chars = string.gmatch(text, '.') +M.iterlen(chars) -- => 3 +chars() -- => nil ```` ### castArray (value) @@ -1734,6 +2024,16 @@ local f = M.unary(function (...) return ... end) f('a','b','c') -- => 'a' ```` +### noarg (f) + +Returns a function with an arity of 0. The new function ignores any arguments passed to it. + +```lua +local f = M.noarg(function (x) return x or 'default' end) +f(1) -- => 'default' +f(function() end, 3) -- => 'default' +```` + ### rearg (f, indexes) Returns a function which runs with arguments arranged according to given `indexes`. @@ -1972,6 +2272,26 @@ M.path(entity,'engine','right','damage') -- => 10 M.path(entity,'boost') -- => false ```` +### spreadPath (obj, ...) + +Spreads object under property path onto provided object. It is similar to `flattenPath`, but removes object under the property path. + +```lua +local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} +M.spreadPath(obj, 'c', 'f') +-- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {f = {}}} +```` + +### flattenPath (obj, ...) + +Flattens object under property path onto provided object. It is similar to `spreadPath`, but preserves object under the property path. + +```lua +local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} +M.spreadPath(obj, 'c', 'f') +-- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {d = 3, e = 4, f = {g = 5}}} +```` + ### kvpairs (obj) Converts an object to an array-list of key-value pairs. @@ -1998,6 +2318,16 @@ obj = M.toObj(list_pairs) -- => {x = 1, y = 2, z = 3} ```` +### invert (obj) +*Aliases: `mirror`*. + +Switches <tt>key-value</tt> pairs: + +```lua +M.invert {'a','b','c'} -- => "{a=1, b=2, c=3}" +M.invert {x = 1, y = 2} -- => "{'x','y'}" +```` + ### property (key) Returns a function that will return the key property of any passed-in object. @@ -2067,7 +2397,7 @@ print(obj2 == obj) -- => false print(M.isEqual(obj2, obj)) -- => true ```` -### tap (obj, f [, ...]) +### tap (obj, f) Invokes a given interceptor function on some object, and then returns the object itself. Useful to tap into method chaining to hook intermediate results. The passed-in interceptor should be prototyped as `f(obj,...)`. @@ -2132,7 +2462,7 @@ M.isEqual(3.14,math.pi) -- => false M.isEqual({3,4,5},{3,4,{5}}) -- => false ```` -### result (obj, method [, ...]) +### result (obj, method) Calls an object method, passing it as a first argument the object itself. @@ -2183,6 +2513,17 @@ M.isIterable(false) -- => false M.isIterable(1) -- => false ```` +### type (obj) + +Extends Lua's `type` function. It returns the type of the given object and also recognises 'file' userdata + +```lua +M.type('string') -- => 'string' +M.type(table) -- => 'table' +M.type(function() end) -- => 'function' +M.type(io.open('f','w')) -- => 'file' +```` + ### isEmpty ([obj]) Is the given argument empty ? @@ -2,11 +2,11 @@ -- @author [Roland Yonaba](http://github.com/Yonaba) -- @copyright 2012-2018 -- @license [MIT](http://www.opensource.org/licenses/mit-license.php) --- @release 2.0.0 +-- @release 2.1.0 -- @module moses -- @set sort=true -local _MODULEVERSION = '2.0.0' +local _MODULEVERSION = '2.1.0' -- Internalisation local next, type, pcall = next, type, pcall @@ -258,12 +258,11 @@ end -- <br/><em>Aliased as `forEach`</em>. -- @name each -- @param t a table --- @param f a function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f a function, prototyped as `f (v, k)` -- @see eachi -function M.each(t, f, ...) +function M.each(t, f) for index,value in pairs(t) do - f(value, index, ...) + f(value, index) end end @@ -273,13 +272,12 @@ end -- <br/><em>Aliased as `forEachi`</em>. -- @name eachi -- @param t a table --- @param f a function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f a function, prototyped as `f (v, k)` -- @see each -function M.eachi(t, f, ...) +function M.eachi(t, f) local lkeys = M.sort(M.select(M.keys(t), M.isInteger)) for k, key in ipairs(lkeys) do - f(t[key], key, ...) + f(t[key], key) end end @@ -295,16 +293,15 @@ function M.at(t, ...) end --- Adjusts the value at a given key using a function or a value. In case `f` is a function, --- it should be prototyped `f(v, ...)`. It does not mutate the given table, but rather +-- it should be prototyped `f(v)`. It does not mutate the given table, but rather -- returns a new array. In case the given `key` does not exist in `t`, it throws an error. -- @param t a table -- @param key a key --- @param f a function, prototyped as `f(v, ...)` or a value --- @param[opt] ... Optional args to be passed to `f` -function M.adjust(t, key, f, ...) +-- @param f a function, prototyped as `f(v)` or a value +function M.adjust(t, key, f) if (t[key] == nil) then error("key not existing in table") end local _t = M.clone(t) - _t[key] = type(f) == 'function' and f(_t[key], ...) or f + _t[key] = type(f) == 'function' and f(_t[key]) or f return _t end @@ -325,22 +322,41 @@ function M.count(t, val) end --- Counts the number of values passing a predicate test. Same as @{count}, but uses an iterator. --- Returns the count for values passing the test `f (v, k, ...)` +-- Returns the count for values passing the test `f (v, k)` -- @name countf -- @param t a table --- @param f an iterator function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function, prototyped as `f (v, k)` -- @return the count of values validating the predicate -- @see count -- @see size -function M.countf(t, f, ...) +function M.countf(t, f) local count = 0 for k, v in pairs(t) do - if f(v, k, ...) then count = count + 1 end + if f(v, k) then count = count + 1 end end return count end +--- Checks if all values in a collection are equal. Uses an optional `comp` function which is used +-- to compare values and defaults to @{isEqual} when not given. +-- <br/><em>Aliased as `alleq`</em>. +-- @name allEqual +-- @param t a table +-- @param[opt] comp a comparison function. Defaults to `isEqual` +-- @return `true` when all values in `t` are equal, `false` otherwise. +-- @see isEqual +function M.allEqual(t, comp) + local k, pivot = next(t) + for k, v in pairs(t) do + if comp then + if not comp(pivot, v) then return false end + else + if not M.isEqual(pivot, v) then return false end + end + end + return true +end + --- Loops `n` times through a table. In case `n` is omitted, it will loop forever. -- In case `n` is lower or equal to 0, it returns an empty function. -- <br/><em>Aliased as `loop`</em>. @@ -372,13 +388,12 @@ end -- <br/><em>Aliased as `collect`</em>. -- @name map -- @param t a table --- @param f an iterator function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function, prototyped as `f (v, k)` -- @return a table of results -function M.map(t, f, ...) +function M.map(t, f) local _t = {} for index,value in pairs(t) do - local k, kv, v = index, f(value, index, ...) + local k, kv, v = index, f(value, index) _t[v and kv or k] = v or kv end return _t @@ -393,8 +408,9 @@ end -- @param f an iterator function, prototyped as `f (state, value)` -- @param[opt] state an initial state of reduction. Defaults to the first value in the table. -- @return the final state of reduction +-- @see best -- @see reduceRight --- @see reduceby +-- @see reduceBy function M.reduce(t, f, state) for k,value in pairs(t) do if state == nil then state = value @@ -404,18 +420,40 @@ function M.reduce(t, f, state) return state end +--- Returns the best value passing a selector function. Acts as a special case of +-- @{reduce}, using the first value in `t` as an initial state. It thens folds the given table, +-- testing each of its values `v` and selecting the value passing the call `f(state,v)` every time. +-- @name best +-- @param t a table +-- @param f an iterator function, prototyped as `f (state, value)` +-- @return the final state of reduction +-- @see reduce +-- @see reduceRight +-- @see reduceBy +function M.best(t, f) + local _, state = next(t) + for k,value in pairs(t) do + if state == nil then state = value + else state = f(state,value) and state or value + end + end + return state +end + --- Reduces values in a table passing a given predicate. Folds the table left-to-right, considering -- only values validating a given predicate. --- @name reduceby +-- @name reduceBy -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` --- @param pred a predicate function `pred (v, k, ...)` to select values to be considered for reduction +-- @param pred a predicate function `pred (v, k)` to select values to be considered for reduction -- @param[opt] state an initial state of reduction. Defaults to the first value in the table of selected values. -- @param[optchain] ... optional args to be passed to `pred` -- @return the final state of reduction -- @see reduce -function M.reduceby(t, f, pred, state, ...) - return M.reduce(M.select(t, pred, ...), f, state) +-- @see best +-- @see reduceRight +function M.reduceBy(t, f, pred, state) + return M.reduce(M.select(t, pred), f, state) end --- Reduces a table, right-to-left. Folds the table from the last element to the first element @@ -428,6 +466,8 @@ end -- @param[opt] state an initial state of reduction. Defaults to the last value in the table. -- @return the final state of reduction -- @see reduce +-- @see best +-- @see reduceBy function M.reduceRight(t, f, state) return M.reduce(M.reverse(t),f,state) end @@ -535,14 +575,13 @@ end -- <br/><em>Aliased as `filter`</em>. -- @name select -- @param t a table --- @param f an iterator function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function, prototyped as `f (v, k)` -- @return the selected values -- @see reject -function M.select(t, f, ...) +function M.select(t, f) local _t = {} for index,value in pairs(t) do - if f(value,index,...) then _t[#_t+1] = value end + if f(value,index) then _t[#_t+1] = value end end return _t end @@ -551,14 +590,13 @@ end -- <br/><em>Aliased as `discard`</em> -- @name reject -- @param t a table --- @param f an iterator function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function, prototyped as `f (v, k)` -- @return the remaining values -- @see select -function M.reject(t, f, ...) +function M.reject(t, f) local _t = {} for index,value in pairs (t) do - if not f(value,index,...) then _t[#_t+1] = value end + if not f(value,index) then _t[#_t+1] = value end end return _t end @@ -567,12 +605,11 @@ end -- <br/><em>Aliased as `every`</em> -- @name all -- @param t a table --- @param f an iterator function, prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function, prototyped as `f (v, k)` -- @return `true` if all values passes the predicate, `false` otherwise -function M.all(t, f, ...) +function M.all(t, f) for index,value in pairs(t) do - if not f(value,index,...) then return false end + if not f(value,index) then return false end end return true end @@ -580,27 +617,25 @@ end --- Invokes a method on each value in a table. -- @name invoke -- @param t a table --- @param method a function, prototyped as `f (v, ...)` --- @param[opt] ... Optional args to be passed to `method` --- @return the result of the call `f (v, ...)` +-- @param method a function, prototyped as `f (v, k)` +-- @return the result of the call `f (v, k)` -- @see pluck -function M.invoke(t, method, ...) - local args = {...} - return M.map(t, function(v) +function M.invoke(t, method) + return M.map(t, function(v, k) if (type(v) == 'table') then if v[method] then if M.isCallable(v[method]) then - return v[method](v,unpack(args)) + return v[method](v,k) else return v[method] end else if M.isCallable(method) then - return method(v,unpack(args)) + return method(v,k) end end elseif M.isCallable(method) then - return method(v,unpack(args)) + return method(v,k) end end) end @@ -622,24 +657,22 @@ end -- be used to evaluate values by which all objects will be sorted. -- @name max -- @param t a table --- @param[opt] transform a transformation function, prototyped as `transform (v, ...)`, defaults to @{identity} --- @param[optchain] ... Optional args to be passed to `transform` +-- @param[opt] transform a transformation function, prototyped as `transform (v, k)`, defaults to @{identity} -- @return the max value found -- @see min -function M.max(t, transform, ...) - return extract(t, f_max, transform, ...) +function M.max(t, transform) + return extract(t, f_max, transform) end --- Returns the min value in a collection. If a `transform` function is passed, it will -- be used to evaluate values by which all objects will be sorted. -- @name min -- @param t a table --- @param[opt] transform a transformation function, prototyped as `transform (v, ...)`, defaults to @{identity} --- @param[optchain] ... Optional args to be passed to `transform` +-- @param[opt] transform a transformation function, prototyped as `transform (v, k)`, defaults to @{identity} -- @return the min value found -- @see max -function M.min(t, transform, ...) - return extract(t, f_min, transform, ...) +function M.min(t, transform) + return extract(t, f_min, transform) end --- Checks if two tables are the same. It compares if both tables features the same values, @@ -664,6 +697,41 @@ function M.sort(t, comp) return t end +--- Iterates on values with respect to key order. Keys are sorted using `comp` function +-- which defaults to `math.min`. It returns upon each call a `key, value` pair. +-- @name sortedk +-- @param t a table +-- @param[opt] comp a comparison function. Defaults to `<` operator +-- @return an iterator function +-- @see sortedv +function M.sortedk(t, comp) + local keys = M.keys(t) + t_sort(keys, comp) + local i = 0 + return function () + i = i + 1 + return keys[i], t[keys[i]] + end +end + +--- Iterates on values with respect to values order. Values are sorted using `comp` function +-- which defaults to `math.min`. It returns upon each call a `key, value` pair. +-- @name sortedv +-- @param t a table +-- @param[opt] comp a comparison function. Defaults to `<` operator +-- @return an iterator function +-- @see sortedk +function M.sortedv(t, comp) + local keys = M.keys(t) + comp = comp or f_min + t_sort(keys, function(a,b) return comp(t[a],t[b]) end) + local i = 0 + return function () + i = i + 1 + return keys[i], t[keys[i]] + end +end + --- Sorts a table in-place using a transform. Values are ranked in a custom order of the results of -- running `transform (v)` on all values. `transform` may also be a string name property sort by. -- `comp` is a comparison function. @@ -686,14 +754,12 @@ end --- Splits a table into subsets groups. -- @name groupBy -- @param t a table --- @param iter an iterator function, prototyped as `iter (v, k, ...)` --- @param[opt] ... Optional args to be passed to `iter` +-- @param iter an iterator function, prototyped as `iter (v, k)` -- @return a table of subsets groups -function M.groupBy(t, iter, ...) - local vararg = {...} +function M.groupBy(t, iter) local _t = {} for k,v in pairs(t) do - local _key = iter(v,k, unpack(vararg)) + local _key = iter(v,k) if _t[_key] then _t[_key][#_t[_key]+1] = v else _t[_key] = {v} end @@ -704,14 +770,13 @@ end --- Groups values in a collection and counts them. -- @name countBy -- @param t a table --- @param iter an iterator function, prototyped as `iter (v, k, ...)` --- @param[opt] ... Optional args to be passed to `iter` +-- @param iter an iterator function, prototyped as `iter (v, k)` -- @return a table of subsets groups names paired with their count -function M.countBy(t, iter, ...) +function M.countBy(t, iter) local stats = {} for i,v in pairs(t) do - local key = iter(v,i,...) - stats[key] = (stats[key] or 0) +1 + local key = iter(v,i) + stats[key] = (stats[key] or 0)+1 end return stats end @@ -800,6 +865,26 @@ function M.sampleProb(array, prob, seed) return t end +--- Returns the n-top values satisfying a predicate. It takes a comparison function +-- `comp` used to sort array values, and then picks the top n-values. It leaves the original array untouched. +-- @name nsorted +-- @param array an array +-- @param[opt] n a number of values to retrieve. Defaults to 1. +-- @param[optchain] comp a comparison function. Defaults to `<` operator. +-- @return an array of top n values +function M.nsorted(array, n, comp) + comp = comp or f_min + n = n or 1 + local values, count = {}, 0 + for k, v in M.sortedv(array, comp) do + if count < n then + count = count + 1 + values[count] = v + end + end + return values +end + --- Returns a shuffled copy of a given array. If a seed is provided, it will -- be used to init the built-in pseudo random number generator (using `math.randomseed`). -- @name shuffle @@ -818,10 +903,10 @@ function M.shuffle(array, seed) end --- Converts a list of arguments to an array. --- @name toArray +-- @name pack -- @param ... a list of arguments -- @return an array of all passed-in args -function M.toArray(...) return {...} end +function M.pack(...) return {...} end --- Looks for the first occurrence of a given value in an array. Returns the value index if found. -- Uses @{isEqual} to compare values. @@ -894,14 +979,13 @@ function M.vector(value, n) return M.fill({}, value, 1, n) end -- <br/><em>Aliased as `takeWhile`</em> -- @name selectWhile -- @param array an array --- @param f an iterator function prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function prototyped as `f (v, k)` -- @return a new table containing all values collected -- @see dropWhile -function M.selectWhile(array, f, ...) +function M.selectWhile(array, f) local t = {} for i,v in ipairs(array) do - if f(v,i,...) then t[i] = v else break end + if f(v,i) then t[i] = v else break end end return t end @@ -911,14 +995,13 @@ end -- <br/><em>Aliased as `rejectWhile`</em> -- @name dropWhile -- @param array an array --- @param f an iterator function prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function prototyped as `f (v, k)` -- @return a new table containing all values collected -- @see selectWhile -function M.dropWhile(array, f, ...) +function M.dropWhile(array, f) local _i for i,v in ipairs(array) do - if not f(v, i, ...) then + if not f(v, i) then _i = i break end @@ -971,25 +1054,23 @@ end --- Returns the first index at which a predicate returns true. -- @name findIndex -- @param array an array --- @param predicate a predicate function prototyped as `predicate (v, k, ...)` --- @param[opt] ... optional arguments to `pred` +-- @param pred a predicate function prototyped as `pred (v, k)` -- @return the index found or __nil__ -- @see findLastIndex -function M.findIndex(array, predicate, ...) +function M.findIndex(array, pred) for k = 1, #array do - if predicate(array[k],k,...) then return k end + if pred(array[k],k) then return k end end end --- Returns the last index at which a predicate returns true. -- @name findLastIndex -- @param array an array --- @param predicate a predicate function prototyped as `predicate (k, v, ...)` --- @param[opt] ... optional arguments to `pred` +-- @param pred a predicate function prototyped as `pred (k, v)` -- @return the index found or __nil__ -- @see findIndex -function M.findLastIndex(array, predicate, ...) - local key = M.findIndex(M.reverse(array),predicate,...) +function M.findLastIndex(array, pred) + local key = M.findIndex(M.reverse(array),pred) if key then return #array-key+1 end end @@ -1009,7 +1090,7 @@ function M.addTop(array, ...) end --- Adds all passed-in values at the top of an array. As opposed to @{addTop}, it preserves the order --- of the passed in elements. +-- of the passed-in elements. -- @name prepend -- @param array an array -- @param ... a variable number of arguments @@ -1077,10 +1158,15 @@ end -- @param ... a variable number of values to be removed from the array -- @return the passed-in array with values removed function M.pull(array, ...) - for k, rmValue in ipairs({...}) do - for i = #array, 1, -1 do - if M.isEqual(array[i], rmValue) then - t_remove(array, i) + local values = {...} + for i = #array, 1, -1 do + local remval = false + for k, rmValue in ipairs(values) do + if (remval == false) then + if M.isEqual(array[i], rmValue) then + t_remove(array, i) + remval = true + end end end end @@ -1107,18 +1193,17 @@ function M.removeRange(array, start, finish) end --- Chunks together consecutive values. Values are chunked on the basis of the return --- value of a provided predicate `f (k, v, ...)`. Consecutive elements which return +-- value of a provided predicate `f (v, k)`. Consecutive elements which return -- the same value are chunked together. Leaves the first argument untouched if it is not an array. -- @name chunk -- @param array an array --- @param f an iterator function prototyped as `f (v, k, ...)` --- @param[opt] ... Optional args to be passed to `f` +-- @param f an iterator function prototyped as `f (v, k)` -- @return a table of chunks (arrays) -- @see zip -function M.chunk(array, f, ...) +function M.chunk(array, f) local ch, ck, prev, val = {}, 0 for k,v in ipairs(array) do - val = f(v, k,...) + val = f(v, k) prev = (prev==nil) and val or prev ck = ((val~=prev) and (ck+1) or ck) if not ch[ck] then @@ -1287,14 +1372,15 @@ end --- Returns the intersection of all passed-in arrays. -- Each value in the result is present in each of the passed-in arrays. -- @name intersection --- @param array an array -- @param ... a variable number of array arguments -- @return a new array -- @see difference -- @see union -- @see symmetricDifference -function M.intersection(array, ...) +function M.intersection(...) local arg = {...} + local array = arg[1] + t_remove(arg, 1) local _intersect = {} for i,value in ipairs(array) do if M.all(arg,function(v) return M.include(v,value) end) then @@ -1304,6 +1390,15 @@ function M.intersection(array, ...) return _intersect end +--- Checks if all passed in arrays are disjunct. +-- @name disjoint +-- @param ... a variable number of arrays +-- @return `true` if the intersection of all arrays is not empty, `false` otherwise. +-- @see intersection +function M.disjoint(...) + return (#M.intersection(...) == 0) +end + --- Performs a symmetric difference. Returns values from `array` not present in `array2` and also values -- from `array2` not present in `array`. -- <br/><em>Aliased as `symdiff`</em> @@ -1327,6 +1422,7 @@ end -- @param array an array -- @return a new array, duplicate-free -- @see isunique +-- @see duplicates function M.unique(array) local ret = {} for i = 1, #array do @@ -1344,10 +1440,27 @@ end -- @param array an array -- @return `true` if the given array is unique, `false` otherwise. -- @see unique +-- @see duplicates function M.isunique(array) return #array == #(M.unique(array)) end +--- Returns an array list of all duplicates in array. +-- @name duplicates +-- @param array an array +-- @return an array-list of duplicates +-- @see unique +function M.duplicates(array) + local dict = M.invert(array) + local dups = {} + for k, v in ipairs(array) do + if dict[v] ~= k and not M.find(dups, v) then + dups[#dups+1] = v + end + end + return dups +end + --- Merges values of each of the passed-in arrays in subsets. -- Only values indexed with the same key in the given arrays are merged in the same subset. -- <br/><em>Aliased as `transpose`</em> @@ -1549,20 +1662,6 @@ function M.permutation(array) end) end ---- Swaps keys with values. Produces a new array where previous keys are now values, --- while previous values are now keys. --- <br/><em>Aliased as `mirror`</em> --- @name invert --- @param array a given array --- @return a new array -function M.invert(array) - local _ret = {} - for k, v in ipairs(array) do - _ret[v] = k - end - return _ret -end - --- Concatenates values in a given array. Handles booleans as well. If `sep` string is -- passed, it will be used as a separator. Passing `i` and `j` will result in concatenating -- only values within `[i, j]` range. @@ -1592,6 +1691,32 @@ function M.xprod(array, array2) return p end +--- Creates pairs from value and array. Value is always prepended to the pair. +-- @name xpairs +-- @param valua a value +-- @param array an array +-- @return an array list of all pairs +function M.xpairs(value, array) + local xpairs = {} + for k, v in ipairs(array) do + xpairs[k] = {value, v} + end + return xpairs +end + +--- Creates pairs from value and array. Value is always appended as the last item to the pair. +-- @name xpairsRight +-- @param valua a value +-- @param array an array +-- @return an array list of all pairs +function M.xpairsRight(value, array) + local xpairs = {} + for k, v in ipairs(array) do + xpairs[k] = {v, value} + end + return xpairs +end + --- Returns the sum of array values. -- @name sum -- @param array a given array @@ -1658,6 +1783,15 @@ function M.noop() return end -- @return the passed-in value function M.identity(value) return value end +--- Calls `f` with the supplied arguments. Returns the results of `f(...)`. +-- @name call +-- @param f a function +-- @param[opt] ... a vararg list of args to `f` +-- @return the result of `f(...)` call. +function M.call(f, ...) + return f(...) +end + --- Creates a constant function which returns the same output on every call. -- <br/><em>Aliased as `always`</em> -- @name constant @@ -1681,6 +1815,68 @@ function M.applySpec(specs) end end +--- Threads `value` through a series of functions. If a function expects more than one args, +-- it can be specified using an array list, where the first item is the function and the following +-- are the remaining args neeeded. The value is used as the first input. +-- @name thread +-- @param value a value +-- @param ... a vararg list of functions or arrays +-- @return a value +-- @see threadRight +function M.thread(value, ...) + local state = value + local arg = {...} + for k, t in ipairs(arg) do + if type(t) == 'function' then + state = t(state) + elseif type(t) == 'table' then + local f = t[1] + t_remove(t, 1) + state = M.reduce(t, f, state) + end + end + return state +end + +--- Threads `value` through a series of functions. If a function expects more than one args, +-- it can be specified using an array list, where the first item is the function and the following +-- are the remaining args neeeded. The value is used as the last input. +-- @name threadRight +-- @param value a value +-- @param ... a vararg list of functions or arrays +-- @return a value +-- @see thread +function M.threadRight(value, ...) + local state = value + local arg = {...} + for k, t in ipairs(arg) do + if type(t) == 'function' then + state = t(state) + elseif type(t) == 'table' then + local f = t[1] + t_remove(t, 1) + t_insert(t, state) + state = M.reduce(t, f) + end + end + return state +end + +--- Returns a dispatching function. When called with arguments, this function invokes each of its functions +-- in the passed-in order and returns the results of the first non-nil evaluation. +-- @name dispatch +-- @param ... a vararg list of functions +-- @return a dispatch function +function M.dispatch(...) + local funcs = {...} + return function (...) + for k, f in ipairs(funcs) do + local r = {f(...)} + if #r > 0 then return unpack(r) end + end + end +end + --- Memoizes a given function by caching the computed result. -- Useful for speeding-up slow-running functions. -- <br/><em>Aliased as `cache`</em> @@ -1839,14 +2035,13 @@ end --- Runs `iter` function `n` times. Collects the results of each run and returns them in an array. -- @name times --- @param iter an iterator function, prototyped as `iter (i, ...)` +-- @param iter an iterator function, prototyped as `iter (i)` -- @param[opt] n the number of times `iter` should be called. Defaults to 1. --- @param[optchain] ... args to be passed to `iter` function -- @return table an array of results -function M.times(iter, n, ...) +function M.times(iter, n) local results = {} for i = 1, (n or 1) do - results[i] = iter(i,...) + results[i] = iter(i) end return results end @@ -1929,21 +2124,65 @@ function M.cond(conds) end end +--- Returns a validation function. Given a set of functions, the validation function evaluates +-- to `true` only when all its funcs returns `true`. +-- @name both +-- @param ... an array list of functions +-- @return `true` when all given funcs returns true with input, false otherwise +function M.both(...) + local funcs = {...} + return function (...) + for k, f in ipairs(funcs) do + if not f(...) then return false end + end + return true + end +end + +--- Returns a validation function. Given a set of functions, the validation function evaluates +-- to `true` when at least one of its funcs returns `true`. +-- @name either +-- @param ... an array list of functions +-- @return `true` when one of the given funcs returns `true` with input, `false` otherwise +function M.either(...) + local funcs = {...} + return function (...) + for k, f in ipairs(funcs) do + if f(...) then return true end + end + return false + end +end + +--- Returns a validation function. Given a set of functions, the validation function evaluates +-- to `true` when neither of its func return `true`. +-- @name neither +-- @param ... an array list of functions +-- @return `true` when neither of the given funcs returns `true` with input, `false` otherwise +function M.neither(...) + local funcs = {...} + return function (...) + for k, f in ipairs(funcs) do + if f(...) then return false end + end + return true + end +end + --- Generates an unique ID for the current session. If given a string `template`, it -- will use this template for output formatting. Otherwise, if `template` is a function, it --- will evaluate `template (id, ...)`. +-- will evaluate `template (id)`. -- <br/><em>Aliased as `uid`</em>. -- @name uniqueId -- @param[opt] template either a string or a function template to format the ID --- @param[optchain] ... a variable number of arguments to be passed to `template`, in case it is a function. -- @return value an ID -function M.uniqueId(template, ...) +function M.uniqueId(template) unique_id_counter = unique_id_counter + 1 if template then if type(template) == 'string' then return template:format(unique_id_counter) elseif type(template) == 'function' then - return template(unique_id_counter,...) + return template(unique_id_counter) end end return unique_id_counter @@ -1967,18 +2206,39 @@ function M.iterator(f, value, n) end end +--- Consumes the first `n` values of a iterator then returns it. +-- @name skip +-- @param iter an iterator function +-- @param[opt] n a number. Defaults to 1. +-- @return the given iterator +function M.skip(iter, n) + for i = 1, (n or 1) do + if iter() == nil then return end + end + return iter +end + --- Iterates over an iterator and returns its values in an array. --- <br/><em>Aliased as `tabulate`</em>. --- @name array +-- @name tabulate -- @param ... an iterator function (returning a generator, a state and a value) -- @return an array of results -function M.array(...) +function M.tabulate(...) local r = {} for v in ... do r[#r+1] = v end return r end ---- Casts vaue as an array if it is not one. +--- Returns the length of an iterator. It consumes the iterator itself. +-- @name iterlen +-- @param ... an iterator function (returning a generator, a state and a value) +-- @return the iterator length +function M.iterlen(...) + local l = 0 + for v in ... do l = l + 1 end + return l +end + +--- Casts value as an array if it is not one. -- @name castArray -- @param value a value -- @return an array containing the given value @@ -2037,6 +2297,16 @@ function M.ary(f, n) end end +--- Returns a function with an arity of 0. The new function ignores any arguments passed to it. +-- @name noarg +-- @param f a function +-- @return a new function +function M.noarg(f) + return function () + return f() + end +end + --- Returns a function which runs with arguments rearranged. Arguments are passed to the -- returned function in the order of supplied `indexes` at call-time. -- @name rearg @@ -2207,7 +2477,7 @@ function M.time(f, ...) end --- Object functions ---@section Object functions +-- @section Object functions --- Returns the keys of the object properties. -- @name keys @@ -2244,6 +2514,43 @@ function M.path(obj, ...) return value end +--- Spreads object under property path onto provided object. +-- It is similar to @{flattenPath}, but removes object under the property path. +-- @name spreadPath +-- @param obj an object +-- @param ... a property path given as a vararg list +-- @return the passed-in object with changes +-- @see flattenPath +function M.spreadPath(obj, ...) + local path = {...} + for _, p in ipairs(path) do + if obj[p] then + for k, v in pairs(obj[p]) do + obj[k] = v + obj[p][k] = nil + end + end + end + return obj +end + +--- Flattens object under property path onto provided object. +-- It is similar to @{spreadPath}, but preserves object under the property path. +-- @name flattenPath +-- @param obj an object +-- @param ... a property path given as a vararg list +-- @return the passed-in object with changes +-- @see spreadPath +function M.flattenPath(obj, ...) + local path = {...} + for _, p in ipairs(path) do + if obj[p] then + for k, v in pairs(obj[p]) do obj[k] = v end + end + end + return obj +end + --- Converts key-value pairs to an array-list of `[k, v]` pairs. -- @name kvpairs -- @param obj an object @@ -2270,6 +2577,20 @@ function M.toObj(kvpairs) return obj end +--- Swaps keys with values. Produces a new object where previous keys are now values, +-- while previous values are now keys. +-- <br/><em>Aliased as `mirror`</em> +-- @name invert +-- @param obj a given object +-- @return a new object +function M.invert(obj) + local _ret = {} + for k, v in pairs(obj) do + _ret[v] = k + end + return _ret +end + --- Returns a function that will return the key property of any passed-in object. -- @name property -- @param key a key property name @@ -2366,11 +2687,10 @@ end -- on intermediate results within the chain. -- @name tap -- @param obj an object --- @param f an interceptor function, should be prototyped as `f (obj, ...)` --- @param[opt] ... args to be passed to `f` +-- @param f an interceptor function, should be prototyped as `f (obj)` -- @return the passed-in object -function M.tap(obj, f, ...) - f(obj,...) +function M.tap(obj, f) + f(obj) return obj end @@ -2441,6 +2761,7 @@ end -- @param objB another object -- @param[opt] useMt whether or not `__eq` should be used, defaults to false. -- @return `true` or `false` +-- @see allEqual function M.isEqual(objA, objB, useMt) local typeObjA = type(objA) local typeObjB = type(objB) @@ -2477,17 +2798,16 @@ end -- @name result -- @param obj an object -- @param method a string key to index in object `obj`. --- @param[opt] ... Optional args to be passed to `method` --- @return the returned value of `method (obj, ...)` call -function M.result(obj, method, ...) +-- @return the returned value of `method (obj)` call +function M.result(obj, method) if obj[method] then if M.isCallable(obj[method]) then - return obj[method](obj,...) + return obj[method](obj) else return obj[method] end end if M.isCallable(method) then - return method(obj,...) + return method(obj) end end @@ -2536,6 +2856,22 @@ function M.isIterable(obj) return M.toBoolean((pcall(pairs, obj))) end +--- Extends Lua's `type` function. It returns the type of the given object and also recognises +-- file userdata +-- @name type +-- @param obj an object +-- @return the given object type +function M.type(obj) + local tp = type(obj) + if tp == 'userdata' then + local mt = getmetatable(obj) + if mt == getmetatable(io.stdout) then + return 'file' + end + end + return tp +end + --- Checks if the given pbject is empty. If `obj` is a string, will return `true` -- if `#obj == 0`. Otherwise, if `obj` is a table, will return whether or not this table -- is empty. If `obj` is `nil`, it will return true. @@ -2624,6 +2960,7 @@ do M.forEach = M.each M.forEachi = M.eachi M.update = M.adjust + M.alleq = M.allEqual M.loop = M.cycle M.collect = M.map M.inject = M.reduce @@ -2650,7 +2987,6 @@ do M.head = M.first M.take = M.first M.tail = M.rest - M.skip = M.last M.without = M.difference M.diff = M.difference M.symdiff = M.symmetricDifference @@ -2673,7 +3009,6 @@ do M.juxt = M.juxtapose M.uid = M.uniqueid M.iter = M.iterator - M.tabulate = M.array M.nAry = M.ary -- Object functions aliases diff --git a/moses_min.lua b/moses_min.lua index fe6a9b3..e2117cb 100644 --- a/moses_min.lua +++ b/moses_min.lua @@ -1,4 +1,4 @@ -local SWFtRywD='2.0.0'local e,v,l6Sm5=next,type,pcall;local oUA,QFKEzBf=setmetatable,getmetatable +local SWFtRywD='2.1.0'local e,v,l6Sm5=next,type,pcall;local oUA,QFKEzBf=setmetatable,getmetatable local odpE,p=table.insert,table.sort;local lIpFkbLI,JdUtcU=table.remove,table.concat local GQLN,toXyq,S9TO=math.randomseed,math.random,math.huge;local pS78Y,BCf7,RlMSrmdD,VCD=math.floor,math.max,math.min,math.ceil local OV7=coroutine.wrap;local X83a=coroutine.yield;local PizLA9mj=rawget @@ -51,423 +51,474 @@ S1wg_DG.operator.lor=function(EEOUzhy,hbrt)return EEOUzhy or hbrt end;S1wg_DG.op Q..mRqle end;S1wg_DG.operator.length=function(sBEZ8)return #sBEZ8 end S1wg_DG.operator.len=S1wg_DG.operator.length;function S1wg_DG.clear(WhHB0ygh)for rYSD0 in l(WhHB0ygh)do WhHB0ygh[rYSD0]=nil end -return WhHB0ygh end -function S1wg_DG.each(BIL5,GQLlkH,...)for aN4J2zRQ,eWca in l(BIL5)do -GQLlkH(eWca,aN4J2zRQ,...)end end -function S1wg_DG.eachi(AGUR2QK,FK,...) +return WhHB0ygh end;function S1wg_DG.each(BIL5,GQLlkH)for aN4J2zRQ,eWca in l(BIL5)do +GQLlkH(eWca,aN4J2zRQ)end end +function S1wg_DG.eachi(AGUR2QK,FK) local _=S1wg_DG.sort(S1wg_DG.select(S1wg_DG.keys(AGUR2QK),S1wg_DG.isInteger)) -for YQZ729qQ,rZh2wG in kyWtqIf0(_)do FK(AGUR2QK[rZh2wG],rZh2wG,...)end end;function S1wg_DG.at(sef4eW6Q,...)local Z={} +for YQZ729qQ,rZh2wG in kyWtqIf0(_)do FK(AGUR2QK[rZh2wG],rZh2wG)end end;function S1wg_DG.at(sef4eW6Q,...)local Z={} for UacO6D,FdnzjW in kyWtqIf0({...})do Z[#Z+1]=sef4eW6Q[FdnzjW]end;return Z end -function S1wg_DG.adjust(o,lMAL,CpQ,...) +function S1wg_DG.adjust(o,lMAL,CpQ) if( o[lMAL]==nil)then zupvsz("key not existing in table")end;local L=S1wg_DG.clone(o)L[lMAL]= -v(CpQ)=='function'and CpQ(L[lMAL],...)or CpQ;return L end +v(CpQ)=='function'and CpQ(L[lMAL])or CpQ;return L end function S1wg_DG.count(HnQS_Z,rib) if rib==nil then return S1wg_DG.size(HnQS_Z)end;local hgW2H5=0;for w,YT6wZ in l(HnQS_Z)do if S1wg_DG.isEqual(YT6wZ,rib)then hgW2H5=hgW2H5+1 end end;return hgW2H5 end -function S1wg_DG.countf(VYv,gU,...)local hgW2H5=0;for JzG8W4Ya,dZ54oc in l(VYv)do -if gU(dZ54oc,JzG8W4Ya,...)then hgW2H5=hgW2H5+1 end end;return hgW2H5 end -function S1wg_DG.cycle(v_LoR,gRY)gRY=gRY or 1;if gRY<=0 then return S1wg_DG.noop end;local z,ad -local Ui0Qa=0 +function S1wg_DG.countf(VYv,gU)local hgW2H5=0;for JzG8W4Ya,dZ54oc in l(VYv)do +if gU(dZ54oc,JzG8W4Ya)then hgW2H5=hgW2H5+1 end end;return hgW2H5 end +function S1wg_DG.allEqual(v_LoR,gRY)local z,ad=e(v_LoR) +for z,Ui0Qa in l(v_LoR)do if gRY then +if not gRY(ad,Ui0Qa)then return false end else +if not S1wg_DG.isEqual(ad,Ui0Qa)then return false end end end;return true end +function S1wg_DG.cycle(g,Itx)Itx=Itx or 1;if Itx<=0 then return S1wg_DG.noop end +local JpoaGH,cyAcCT;local RCA=0 while true do return -function()z=z and e(v_LoR,z)or e(v_LoR) -ad=not ad and z or ad;if gRY then Ui0Qa=(z==ad)and Ui0Qa+1 or Ui0Qa -if Ui0Qa>gRY then return end end;return v_LoR[z],z end end end -function S1wg_DG.map(g,Itx,...)local JpoaGH={}for cyAcCT,RCA in l(g)do local L46S,GKTYT,hXSTz8FJ=cyAcCT,Itx(RCA,cyAcCT,...) -JpoaGH[hXSTz8FJ and -GKTYT or L46S]=hXSTz8FJ or GKTYT end -return JpoaGH end;function S1wg_DG.reduce(C24r7o4G,b_4Q38cU,N) -for JbPw,j in l(C24r7o4G)do if N==nil then N=j else N=b_4Q38cU(N,j)end end;return N end -function S1wg_DG.reduceby(S,cg4FV7bl,flf9sWX,uNoS,...)return -S1wg_DG.reduce(S1wg_DG.select(S,flf9sWX,...),cg4FV7bl,uNoS)end -function S1wg_DG.reduceRight(ZWoH9V08,RWo,GWBQL)return -S1wg_DG.reduce(S1wg_DG.reverse(ZWoH9V08),RWo,GWBQL)end -function S1wg_DG.mapReduce(PCldTUn9,sO_,ALbdmINL)local b={} -for DUgF0E,vGxJ6f in l(PCldTUn9)do b[DUgF0E]=not ALbdmINL and vGxJ6f or -sO_(ALbdmINL,vGxJ6f)ALbdmINL=b[DUgF0E]end;return b end -function S1wg_DG.mapReduceRight(a4ga2I,syGyB_,VO)return -S1wg_DG.mapReduce(S1wg_DG.reverse(a4ga2I),syGyB_,VO)end -function S1wg_DG.include(J1r,iBcU3_7D)local N=(v(iBcU3_7D)=='function')and iBcU3_7D or -S1wg_DG.isEqual;for M4V,_feve in l(J1r)do if -N(_feve,iBcU3_7D)then return true end end;return false end -function S1wg_DG.detect(OPz_7bk,H64aD) -local ny7=(v(H64aD)=='function')and H64aD or S1wg_DG.isEqual -for QDj6GAX,k6pXzd in l(OPz_7bk)do if ny7(k6pXzd,H64aD)then return QDj6GAX end end end -function S1wg_DG.where(hsLwu,R) -local JKZ=S1wg_DG.select(hsLwu,function(yHbsh)for d4z in l(R)do -if yHbsh[d4z]~=R[d4z]then return false end end;return true end)return#JKZ>0 and JKZ or nil end -function S1wg_DG.findWhere(i,HyEk4lbh) -local PhU=S1wg_DG.detect(i,function(rWwbNge)for SKxD in l(HyEk4lbh)do if HyEk4lbh[SKxD]~=rWwbNge[SKxD]then -return false end end -return true end)return PhU and i[PhU]end -function S1wg_DG.select(o3uQKvJ,vAZm,...)local q={}for fFuE,KypMW in l(o3uQKvJ)do -if vAZm(KypMW,fFuE,...)then q[#q+1]=KypMW end end;return q end -function S1wg_DG.reject(JJT4nKO,TFLF,...)local hEoAa={} -for PGN,K2_kF5 in l(JJT4nKO)do if not TFLF(K2_kF5,PGN,...)then -hEoAa[#hEoAa+1]=K2_kF5 end end;return hEoAa end -function S1wg_DG.all(YpimJ,Gg7Ttui,...)for _,EGeAf in l(YpimJ)do -if not Gg7Ttui(EGeAf,_,...)then return false end end;return true end -function S1wg_DG.invoke(ymP,z5pHKyoa,...)local h={...} +function()JpoaGH=JpoaGH and e(g,JpoaGH)or e(g)cyAcCT=not +cyAcCT and JpoaGH or cyAcCT;if Itx then RCA= +(JpoaGH==cyAcCT)and RCA+1 or RCA +if RCA>Itx then return end end;return g[JpoaGH],JpoaGH end end end +function S1wg_DG.map(L46S,GKTYT)local hXSTz8FJ={} +for C24r7o4G,b_4Q38cU in l(L46S)do local N,JbPw,j=C24r7o4G,GKTYT(b_4Q38cU,C24r7o4G)hXSTz8FJ[ +j and JbPw or N]=j or JbPw end;return hXSTz8FJ end +function S1wg_DG.reduce(S,cg4FV7bl,flf9sWX) +for uNoS,ZWoH9V08 in l(S)do if flf9sWX==nil then flf9sWX=ZWoH9V08 else +flf9sWX=cg4FV7bl(flf9sWX,ZWoH9V08)end end;return flf9sWX end +function S1wg_DG.best(RWo,GWBQL)local PCldTUn9,sO_=e(RWo) +for ALbdmINL,b in l(RWo)do if sO_==nil then sO_=b else +sO_=GWBQL(sO_,b)and sO_ or b end end;return sO_ end +function S1wg_DG.reduceBy(DUgF0E,vGxJ6f,a4ga2I,syGyB_)return +S1wg_DG.reduce(S1wg_DG.select(DUgF0E,a4ga2I),vGxJ6f,syGyB_)end;function S1wg_DG.reduceRight(VO,J1r,iBcU3_7D) +return S1wg_DG.reduce(S1wg_DG.reverse(VO),J1r,iBcU3_7D)end +function S1wg_DG.mapReduce(N,M4V,_feve)local OPz_7bk={}for H64aD,ny7 in +l(N)do +OPz_7bk[H64aD]=not _feve and ny7 or M4V(_feve,ny7)_feve=OPz_7bk[H64aD]end;return +OPz_7bk end +function S1wg_DG.mapReduceRight(QDj6GAX,k6pXzd,hsLwu)return +S1wg_DG.mapReduce(S1wg_DG.reverse(QDj6GAX),k6pXzd,hsLwu)end +function S1wg_DG.include(R,JKZ) +local yHbsh=(v(JKZ)=='function')and JKZ or S1wg_DG.isEqual;for d4z,i in l(R)do if yHbsh(i,JKZ)then return true end end +return false end +function S1wg_DG.detect(HyEk4lbh,PhU) +local rWwbNge=(v(PhU)=='function')and PhU or S1wg_DG.isEqual +for SKxD,o3uQKvJ in l(HyEk4lbh)do if rWwbNge(o3uQKvJ,PhU)then return SKxD end end end +function S1wg_DG.where(vAZm,q) +local fFuE=S1wg_DG.select(vAZm,function(KypMW)for JJT4nKO in l(q)do +if KypMW[JJT4nKO]~=q[JJT4nKO]then return false end end;return true end)return#fFuE>0 and fFuE or nil end +function S1wg_DG.findWhere(TFLF,hEoAa) +local PGN=S1wg_DG.detect(TFLF,function(K2_kF5)for YpimJ in l(hEoAa)do if hEoAa[YpimJ]~=K2_kF5[YpimJ]then +return false end end;return true end)return PGN and TFLF[PGN]end +function S1wg_DG.select(Gg7Ttui,_)local EGeAf={}for ymP,z5pHKyoa in l(Gg7Ttui)do if _(z5pHKyoa,ymP)then +EGeAf[#EGeAf+1]=z5pHKyoa end end +return EGeAf end +function S1wg_DG.reject(h,xwT)local y33ux={}for Ut,GOijBp in l(h)do if not xwT(GOijBp,Ut)then +y33ux[#y33ux+1]=GOijBp end end;return y33ux end;function S1wg_DG.all(oUi,b2a3) +for xer,SQHAAR in l(oUi)do if not b2a3(SQHAAR,xer)then return false end end;return true end +function S1wg_DG.invoke(qybRcP1,z) return -S1wg_DG.map(ymP,function(xwT) -if(v(xwT)=='table')then -if xwT[z5pHKyoa]then +S1wg_DG.map(qybRcP1,function(N0NaR,FBfW) +if( +v(N0NaR)=='table')then +if N0NaR[z]then if S1wg_DG.isCallable(N0NaR[z])then return +N0NaR[z](N0NaR,FBfW)else return N0NaR[z]end else if +S1wg_DG.isCallable(z)then return z(N0NaR,FBfW)end end elseif S1wg_DG.isCallable(z)then return z(N0NaR,FBfW)end end)end +function S1wg_DG.pluck(lnM4,_oDmX_)local t={}for K,ppm021I in l(lnM4)do +if ppm021I[_oDmX_]then t[#t+1]=ppm021I[_oDmX_]end end;return t end;function S1wg_DG.max(ASUXhD,KCm)return z5i2i(ASUXhD,sf0,KCm)end;function S1wg_DG.min(u,fDk)return +z5i2i(u,qxZa6ozV,fDk)end +function S1wg_DG.same(gxYY,sVMxk)return +S1wg_DG.all(gxYY,function(SyD)return +S1wg_DG.include(sVMxk,SyD)end)and S1wg_DG.all(sVMxk,function(v4)return +S1wg_DG.include(gxYY,v4)end)end;function S1wg_DG.sort(j7siW,Hl)p(j7siW,Hl)return j7siW end +function S1wg_DG.sortedk(AP060rq,DIEKD10) +local lLJ=S1wg_DG.keys(AP060rq)p(lLJ,DIEKD10)local EicsS=0;return function()EicsS=EicsS+1 +return lLJ[EicsS],AP060rq[lLJ[EicsS]]end end +function S1wg_DG.sortedv(JubU,L)local JKci=S1wg_DG.keys(JubU)L=L or qxZa6ozV +p(JKci,function(o,ZOmcmO)return +L(JubU[o],JubU[ZOmcmO])end)local SsBe=0;return +function()SsBe=SsBe+1;return JKci[SsBe],JubU[JKci[SsBe]]end end +function S1wg_DG.sortBy(_G19JrRB,m0r3_J,MLrs)local hP5=m0r3_J or S1wg_DG.identity if -S1wg_DG.isCallable(xwT[z5pHKyoa])then return xwT[z5pHKyoa](xwT,hUL(h))else return xwT[z5pHKyoa]end else -if S1wg_DG.isCallable(z5pHKyoa)then return z5pHKyoa(xwT,hUL(h))end end elseif S1wg_DG.isCallable(z5pHKyoa)then return z5pHKyoa(xwT,hUL(h))end end)end -function S1wg_DG.pluck(y33ux,Ut)local GOijBp={}for oUi,b2a3 in l(y33ux)do if b2a3[Ut]then -GOijBp[#GOijBp+1]=b2a3[Ut]end end;return GOijBp end -function S1wg_DG.max(xer,SQHAAR,...)return z5i2i(xer,sf0,SQHAAR,...)end -function S1wg_DG.min(qybRcP1,z,...)return z5i2i(qybRcP1,qxZa6ozV,z,...)end -function S1wg_DG.same(N0NaR,FBfW) -return -S1wg_DG.all(N0NaR,function(lnM4)return S1wg_DG.include(FBfW,lnM4)end)and -S1wg_DG.all(FBfW,function(_oDmX_)return S1wg_DG.include(N0NaR,_oDmX_)end)end;function S1wg_DG.sort(tK,ppm021I)p(tK,ppm021I)return tK end -function S1wg_DG.sortBy(ASUXhD,KCm,u)local fDk=KCm or -S1wg_DG.identity;if(v(KCm)=='string')then -fDk=function(ASUXhD)return ASUXhD[KCm]end end;u=u or qxZa6ozV -p(ASUXhD,function(gxYY,sVMxk)return -u(fDk(gxYY),fDk(sVMxk))end)return ASUXhD end -function S1wg_DG.groupBy(SyD,v4,...)local j7siW={...}local Hl={} -for AP060rq,DIEKD10 in l(SyD)do -local lLJ=v4(DIEKD10,AP060rq,hUL(j7siW))if Hl[lLJ]then Hl[lLJ][#Hl[lLJ]+1]=DIEKD10 else -Hl[lLJ]={DIEKD10}end end;return Hl end -function S1wg_DG.countBy(EicsS,JubU,...)local L={}for JKci,SsBe in l(EicsS)do local o=JubU(SsBe,JKci,...) -L[o]=(L[o]or 0)+1 end;return L end -function S1wg_DG.size(...)local ZOmcmO={...}local _G19JrRB=ZOmcmO[1]return - -(v(_G19JrRB)=='table')and hgW2H5(ZOmcmO[1])or hgW2H5(ZOmcmO)end;function S1wg_DG.containsKeys(m0r3_J,MLrs) -for hP5 in l(MLrs)do if not m0r3_J[hP5]then return false end end;return true end -function S1wg_DG.sameKeys(oqjhEZb0,Pha)for G in -l(oqjhEZb0)do if not Pha[G]then return false end end -for MOrzq4 in l(Pha)do if not -oqjhEZb0[MOrzq4]then return false end end;return true end -function S1wg_DG.sample(bEMp,dd,MOQN)dd=dd or 1;if dd==0 then return{}end -if dd==1 then -if MOQN then GQLN(MOQN)end;return{bEMp[toXyq(1,#bEMp)]}end -return S1wg_DG.slice(S1wg_DG.shuffle(bEMp,MOQN),1,dd)end -function S1wg_DG.sampleProb(O,FEpet,P)if P then GQLN(P)end;local G={}for EcLLM,wo in kyWtqIf0(O)do if toXyq()<FEpet then -G[#G+1]=wo end end;return G end -function S1wg_DG.shuffle(ur,XTX)if XTX then GQLN(XTX)end;local wc8hjKp1={}for f,Hjag in kyWtqIf0(ur)do local Yg= -pS78Y(toXyq()*f)+1;wc8hjKp1[f]=wc8hjKp1[Yg] -wc8hjKp1[Yg]=Hjag end;return wc8hjKp1 end;function S1wg_DG.toArray(...)return{...}end;function S1wg_DG.find(uc,bw,ad) -for EG344W=ad or 1,#uc do if -S1wg_DG.isEqual(uc[EG344W],bw)then return EG344W end end end;function S1wg_DG.reverse(MVlUhPEM) -local LT={} -for pfiWYrg=#MVlUhPEM,1,-1 do LT[#LT+1]=MVlUhPEM[pfiWYrg]end;return LT end -function S1wg_DG.fill(smnX9H6,FzRhHR,mMBxOoQa,xYSLIT)xYSLIT= -xYSLIT or S1wg_DG.size(smnX9H6)for mMBxOoQa=mMBxOoQa or 1,xYSLIT do -smnX9H6[mMBxOoQa]=FzRhHR end;return smnX9H6 end -function S1wg_DG.zeros(Eae7ILmk)return S1wg_DG.fill({},0,1,Eae7ILmk)end -function S1wg_DG.ones(Jy23ZRAA)return S1wg_DG.fill({},1,1,Jy23ZRAA)end -function S1wg_DG.vector(V8IWw,uyYdf)return S1wg_DG.fill({},V8IWw,1,uyYdf)end -function S1wg_DG.selectWhile(K,ZX,...)local tbdC={}for VaY3,HK7Mbgze in kyWtqIf0(K)do -if ZX(HK7Mbgze,VaY3,...)then tbdC[VaY3]=HK7Mbgze else break end end;return tbdC end -function S1wg_DG.dropWhile(VXPfx,j3Qk,...)local X1;for GpruB,r in kyWtqIf0(VXPfx)do -if not j3Qk(r,GpruB,...)then X1=GpruB;break end end;if(X1 ==nil)then return{}end;return -S1wg_DG.rest(VXPfx,X1)end -function S1wg_DG.sortedIndex(V7YqV,JbvH7,Cqk9Luq,PeAP9X)local vN5AF9=Cqk9Luq or qxZa6ozV;if(PeAP9X==true)then -p(V7YqV,vN5AF9)end;for j=1,#V7YqV do -if not vN5AF9(V7YqV[j],JbvH7)then return j end end;return#V7YqV+1 end;function S1wg_DG.indexOf(EOgmP,j) -for mJof=1,#EOgmP do if EOgmP[mJof]==j then return mJof end end end -function S1wg_DG.lastIndexOf(yz1Kuwby,KVE6TG) -local YY=S1wg_DG.indexOf(S1wg_DG.reverse(yz1Kuwby),KVE6TG)if YY then return#yz1Kuwby-YY+1 end end;function S1wg_DG.findIndex(r9,mtUG,...) -for PFRuf=1,#r9 do if mtUG(r9[PFRuf],PFRuf,...)then return PFRuf end end end -function S1wg_DG.findLastIndex(KhK1gRj9,Xgj,...) -local Ko=S1wg_DG.findIndex(S1wg_DG.reverse(KhK1gRj9),Xgj,...)if Ko then return#KhK1gRj9-Ko+1 end end;function S1wg_DG.addTop(A,...) -for IU6Om,sKIIqz in kyWtqIf0({...})do odpE(A,1,sKIIqz)end;return A end;function S1wg_DG.prepend(wmhARqEa,...)return -S1wg_DG.append({...},wmhARqEa)end;function S1wg_DG.push(_RT3,...) -local V={...} -for BTA,QVEYENaX in kyWtqIf0({...})do _RT3[#_RT3+1]=QVEYENaX end;return _RT3 end -function S1wg_DG.shift(gxqa,q4)q4=RlMSrmdD( -q4 or 1,#gxqa)local QyKi={}for _o3FE=1,q4 do local n=gxqa[1] -QyKi[#QyKi+1]=n;lIpFkbLI(gxqa,1)end;return hUL(QyKi)end -function S1wg_DG.unshift(WM,zb8b)zb8b=RlMSrmdD(zb8b or 1,#WM)local YBqeh={} -for WRkIg=1,zb8b do -local RH_vLUg=WM[#WM]YBqeh[#YBqeh+1]=RH_vLUg;lIpFkbLI(WM)end;return hUL(YBqeh)end -function S1wg_DG.pull(aEH,...) -for g20N7,puZN in kyWtqIf0({...})do for _Dy=#aEH,1,-1 do if S1wg_DG.isEqual(aEH[_Dy],puZN)then -lIpFkbLI(aEH,_Dy)end end end;return aEH end -function S1wg_DG.removeRange(MC,WOBSVeqF,A)WOBSVeqF=WOBSVeqF or 1;A=A or#MC;if WOBSVeqF>A then +(v(m0r3_J)=='string')then hP5=function(_G19JrRB)return _G19JrRB[m0r3_J]end end;MLrs=MLrs or qxZa6ozV +p(_G19JrRB,function(oqjhEZb0,Pha) +return MLrs(hP5(oqjhEZb0),hP5(Pha))end)return _G19JrRB end +function S1wg_DG.groupBy(G,MOrzq4)local bEMp={} +for dd,MOQN in l(G)do local O=MOrzq4(MOQN,dd)if bEMp[O]then +bEMp[O][#bEMp[O]+1]=MOQN else bEMp[O]={MOQN}end end;return bEMp end +function S1wg_DG.countBy(FEpet,P)local G={}for EcLLM,wo in l(FEpet)do local ur=P(wo,EcLLM) +G[ur]=(G[ur]or 0)+1 end;return G end;function S1wg_DG.size(...)local XTX={...}local wc8hjKp1=XTX[1] +return(v(wc8hjKp1)=='table')and +hgW2H5(XTX[1])or hgW2H5(XTX)end +function S1wg_DG.containsKeys(f,Hjag)for Yg in +l(Hjag)do if not f[Yg]then return false end end;return true end +function S1wg_DG.sameKeys(uc,bw) +for ad in l(uc)do if not bw[ad]then return false end end +for EG344W in l(bw)do if not uc[EG344W]then return false end end;return true end +function S1wg_DG.sample(MVlUhPEM,LT,pfiWYrg)LT=LT or 1;if LT==0 then return{}end +if LT==1 then +if pfiWYrg then GQLN(pfiWYrg)end;return{MVlUhPEM[toXyq(1,#MVlUhPEM)]}end +return S1wg_DG.slice(S1wg_DG.shuffle(MVlUhPEM,pfiWYrg),1,LT)end +function S1wg_DG.sampleProb(smnX9H6,FzRhHR,mMBxOoQa)if mMBxOoQa then GQLN(mMBxOoQa)end;local xYSLIT={}for Eae7ILmk,Jy23ZRAA in +kyWtqIf0(smnX9H6)do +if toXyq()<FzRhHR then xYSLIT[#xYSLIT+1]=Jy23ZRAA end end;return xYSLIT end +function S1wg_DG.nsorted(V8IWw,uyYdf,K)K=K or qxZa6ozV;uyYdf=uyYdf or 1;local ZX,hgW2H5={},0;for tbdC,VaY3 in +S1wg_DG.sortedv(V8IWw,K)do +if hgW2H5 <uyYdf then hgW2H5=hgW2H5+1;ZX[hgW2H5]=VaY3 end end;return ZX end +function S1wg_DG.shuffle(HK7Mbgze,VXPfx)if VXPfx then GQLN(VXPfx)end;local j3Qk={}for X1,GpruB in kyWtqIf0(HK7Mbgze)do local r=pS78Y( +toXyq()*X1)+1;j3Qk[X1]=j3Qk[r] +j3Qk[r]=GpruB end;return j3Qk end;function S1wg_DG.pack(...)return{...}end;function S1wg_DG.find(V7YqV,JbvH7,Cqk9Luq) +for PeAP9X=Cqk9Luq or 1,#V7YqV do if +S1wg_DG.isEqual(V7YqV[PeAP9X],JbvH7)then return PeAP9X end end end +function S1wg_DG.reverse(vN5AF9) +local j={}for EOgmP=#vN5AF9,1,-1 do j[#j+1]=vN5AF9[EOgmP]end;return j end +function S1wg_DG.fill(jmJof,yz1Kuwby,KVE6TG,YY)YY=YY or S1wg_DG.size(jmJof)for KVE6TG=KVE6TG or 1,YY do +jmJof[KVE6TG]=yz1Kuwby end;return jmJof end +function S1wg_DG.zeros(r9)return S1wg_DG.fill({},0,1,r9)end +function S1wg_DG.ones(mtUG)return S1wg_DG.fill({},1,1,mtUG)end +function S1wg_DG.vector(PFRuf,KhK1gRj9)return S1wg_DG.fill({},PFRuf,1,KhK1gRj9)end +function S1wg_DG.selectWhile(Xgj,Ko)local A={}for IU6Om,sKIIqz in kyWtqIf0(Xgj)do +if Ko(sKIIqz,IU6Om)then A[IU6Om]=sKIIqz else break end end;return A end +function S1wg_DG.dropWhile(wmhARqEa,_RT3)local V;for BTA,QVEYENaX in kyWtqIf0(wmhARqEa)do +if not _RT3(QVEYENaX,BTA)then V=BTA;break end end;if(V==nil)then return{}end;return +S1wg_DG.rest(wmhARqEa,V)end +function S1wg_DG.sortedIndex(gxqa,q4,QyKi,_o3FE)local n=QyKi or qxZa6ozV +if(_o3FE==true)then p(gxqa,n)end +for WM=1,#gxqa do if not n(gxqa[WM],q4)then return WM end end;return#gxqa+1 end;function S1wg_DG.indexOf(zb8b,YBqeh) +for WRkIg=1,#zb8b do if zb8b[WRkIg]==YBqeh then return WRkIg end end end +function S1wg_DG.lastIndexOf(RH_vLUg,aEH) +local g20N7=S1wg_DG.indexOf(S1wg_DG.reverse(RH_vLUg),aEH)if g20N7 then return#RH_vLUg-g20N7+1 end end;function S1wg_DG.findIndex(puZN,_Dy) +for MC=1,#puZN do if _Dy(puZN[MC],MC)then return MC end end end +function S1wg_DG.findLastIndex(WOBSVeqF,A) +local vqW6=S1wg_DG.findIndex(S1wg_DG.reverse(WOBSVeqF),A)if vqW6 then return#WOBSVeqF-vqW6+1 end end;function S1wg_DG.addTop(R4oRlgh,...) +for rBRXA,qfFSJN in kyWtqIf0({...})do odpE(R4oRlgh,1,qfFSJN)end;return R4oRlgh end;function S1wg_DG.prepend(Va8fT08T,...)return +S1wg_DG.append({...},Va8fT08T)end;function S1wg_DG.push(d778,...) +local aZT={...} +for ni9je9bJ,uwwNE in kyWtqIf0({...})do d778[#d778+1]=uwwNE end;return d778 end +function S1wg_DG.shift(X40cF,EW)EW=RlMSrmdD( +EW or 1,#X40cF)local asgq={}for IQybL1=1,EW do local hYKT45=X40cF[1] +asgq[#asgq+1]=hYKT45;lIpFkbLI(X40cF,1)end +return hUL(asgq)end +function S1wg_DG.unshift(Rq7,LQ_EIcl)LQ_EIcl=RlMSrmdD(LQ_EIcl or 1,#Rq7)local uaL={} +for gujcrFp=1,LQ_EIcl do local ph06vXj=Rq7[ +#Rq7]uaL[#uaL+1]=ph06vXj;lIpFkbLI(Rq7)end;return hUL(uaL)end +function S1wg_DG.pull(nH0LB4c,...)local ALwJ9={...} +for _X=#nH0LB4c,1,-1 do local ruXMob=false;for E,jcgjAE in kyWtqIf0(ALwJ9)do +if +(ruXMob==false)then if S1wg_DG.isEqual(nH0LB4c[_X],jcgjAE)then lIpFkbLI(nH0LB4c,_X) +ruXMob=true end end end end;return nH0LB4c end +function S1wg_DG.removeRange(BZmaGN,HSav,sDjMr)HSav=HSav or 1;sDjMr=sDjMr or#BZmaGN;if HSav>sDjMr then zupvsz("start cannot be greater than finish.")end -for vqW6=A,WOBSVeqF,-1 do lIpFkbLI(MC,vqW6)end;return MC end -function S1wg_DG.chunk(R4oRlgh,rBRXA,...)local qfFSJN,Va8fT08T,d778,aZT={},0 -for ni9je9bJ,uwwNE in kyWtqIf0(R4oRlgh)do -aZT=rBRXA(uwwNE,ni9je9bJ,...)d778=(d778 ==nil)and aZT or d778 -Va8fT08T=( -(aZT~=d778)and(Va8fT08T+1)or Va8fT08T)if not qfFSJN[Va8fT08T]then -qfFSJN[Va8fT08T]={R4oRlgh[ni9je9bJ]}else -qfFSJN[Va8fT08T][#qfFSJN[Va8fT08T]+1]=R4oRlgh[ni9je9bJ]end;d778=aZT end;return qfFSJN end -function S1wg_DG.slice(X40cF,EW,asgq)local IQybL1={}for hYKT45=EW or 1,asgq or#X40cF do -IQybL1[#IQybL1+1]=X40cF[hYKT45]end;return IQybL1 end -function S1wg_DG.first(Rq7,LQ_EIcl)LQ_EIcl=LQ_EIcl or 1;local uaL={}for gujcrFp=1,LQ_EIcl do -uaL[gujcrFp]=Rq7[gujcrFp]end;return uaL end -function S1wg_DG.initial(ph06vXj,nH0LB4c)local ALwJ9=#ph06vXj -nH0LB4c=nH0LB4c and -ALwJ9- (RlMSrmdD(nH0LB4c,ALwJ9))or ALwJ9-1;local _X={}for ruXMob=1,nH0LB4c do _X[ruXMob]=ph06vXj[ruXMob]end -return _X end -function S1wg_DG.last(E,jcgjAE)local BZmaGN=#E -jcgjAE=jcgjAE and -BZmaGN-RlMSrmdD(jcgjAE-1,BZmaGN-1)or 2;local HSav={}for sDjMr=jcgjAE,BZmaGN do HSav[#HSav+1]=E[sDjMr]end;return -HSav end;function S1wg_DG.rest(biQX3Ut,BLEXN_)local Ljc={} -for fpN7T=BLEXN_ or 1,#biQX3Ut do Ljc[#Ljc+1]=biQX3Ut[fpN7T]end;return Ljc end;function S1wg_DG.nth(FNSk_,LmE)return -FNSk_[LmE]end -function S1wg_DG.compact(pZTFVP)local XL={}for L5vC0Jx,vpONJ in l(pZTFVP)do if vpONJ then -XL[#XL+1]=vpONJ end end;return XL end -function S1wg_DG.flatten(A,LN)LN=LN or false;local dA14qP;local JcQc={} -for hDih6_D,QKbZ464i in kyWtqIf0(A)do -if v(QKbZ464i)=='table'then -dA14qP= -LN and QKbZ464i or S1wg_DG.flatten(QKbZ464i)for F1TsZ,uF2 in kyWtqIf0(dA14qP)do JcQc[#JcQc+1]=uF2 end else JcQc[ -#JcQc+1]=QKbZ464i end end;return JcQc end -function S1wg_DG.difference(T,pC_)if not pC_ then return S1wg_DG.clone(T)end;return -S1wg_DG.select(T,function(ju)return -not S1wg_DG.include(pC_,ju)end)end;function S1wg_DG.union(...) +for biQX3Ut=sDjMr,HSav,-1 do lIpFkbLI(BZmaGN,biQX3Ut)end;return BZmaGN end +function S1wg_DG.chunk(BLEXN_,Ljc)local fpN7T,FNSk_,LmE,pZTFVP={},0 +for XL,L5vC0Jx in kyWtqIf0(BLEXN_)do pZTFVP=Ljc(L5vC0Jx,XL)LmE= +(LmE==nil)and pZTFVP or LmE;FNSk_=( +(pZTFVP~=LmE)and(FNSk_+1)or FNSk_)if +not fpN7T[FNSk_]then fpN7T[FNSk_]={BLEXN_[XL]}else +fpN7T[FNSk_][#fpN7T[FNSk_]+1]=BLEXN_[XL]end;LmE=pZTFVP end;return fpN7T end +function S1wg_DG.slice(vpONJ,A,LN)local dA14qP={}for JcQc=A or 1,LN or#vpONJ do +dA14qP[#dA14qP+1]=vpONJ[JcQc]end;return dA14qP end +function S1wg_DG.first(hDih6_D,QKbZ464i)QKbZ464i=QKbZ464i or 1;local F1TsZ={}for uF2=1,QKbZ464i do +F1TsZ[uF2]=hDih6_D[uF2]end;return F1TsZ end +function S1wg_DG.initial(T,pC_)local ju=#T +pC_=pC_ and ju- (RlMSrmdD(pC_,ju))or ju-1;local deu1={}for IgZ6=1,pC_ do deu1[IgZ6]=T[IgZ6]end;return deu1 end +function S1wg_DG.last(kVRiv3F,kWMf)local DawC=#kVRiv3F;kWMf= +kWMf and DawC-RlMSrmdD(kWMf-1,DawC-1)or 2;local cP={}for w=kWMf,DawC do +cP[#cP+1]=kVRiv3F[w]end;return cP end;function S1wg_DG.rest(UZ,tdH)local ymt={} +for WxGA=tdH or 1,#UZ do ymt[#ymt+1]=UZ[WxGA]end;return ymt end;function S1wg_DG.nth(jBuHkH,E3)return +jBuHkH[E3]end +function S1wg_DG.compact(CZi_zK)local _6KCMph={}for PY3VqYZ8,V in l(CZi_zK)do if V then +_6KCMph[#_6KCMph+1]=V end end;return _6KCMph end +function S1wg_DG.flatten(y,QF)QF=QF or false;local hN;local hVflx4kh={} +for GP,oCZYv2dT in kyWtqIf0(y)do +if v(oCZYv2dT)=='table'then +hN= +QF and oCZYv2dT or S1wg_DG.flatten(oCZYv2dT) +for RLaqM3,PoH in kyWtqIf0(hN)do hVflx4kh[#hVflx4kh+1]=PoH end else hVflx4kh[#hVflx4kh+1]=oCZYv2dT end end;return hVflx4kh end +function S1wg_DG.difference(xM709D,z50) +if not z50 then return S1wg_DG.clone(xM709D)end;return +S1wg_DG.select(xM709D,function(sAPD)return not S1wg_DG.include(z50,sAPD)end)end;function S1wg_DG.union(...) return S1wg_DG.unique(S1wg_DG.flatten({...}))end -function S1wg_DG.intersection(deu1,...)local IgZ6={...}local kVRiv3F={}for kWMf,DawC in -kyWtqIf0(deu1)do +function S1wg_DG.intersection(...)local AVFi={...} +local GGKI=AVFi[1]lIpFkbLI(AVFi,1)local gWaGu={} +for SFKM,j6jQmlbr in kyWtqIf0(GGKI)do if -S1wg_DG.all(IgZ6,function(cP)return S1wg_DG.include(cP,DawC)end)then kVRiv3F[#kVRiv3F+1]=DawC end end -return kVRiv3F end -function S1wg_DG.symmetricDifference(w,UZ)return -S1wg_DG.difference(S1wg_DG.union(w,UZ),S1wg_DG.intersection(w,UZ))end -function S1wg_DG.unique(tdH)local ymt={}for WxGA=1,#tdH do if not S1wg_DG.find(ymt,tdH[WxGA])then -ymt[#ymt+1]=tdH[WxGA]end end;return -ymt end;function S1wg_DG.isunique(jBuHkH)return -#jBuHkH==# (S1wg_DG.unique(jBuHkH))end -function S1wg_DG.zip(...) -local E3={...} -local CZi_zK=S1wg_DG.max(E3,function(PY3VqYZ8)return#PY3VqYZ8 end)local _6KCMph={} -for V=1,CZi_zK do if not _6KCMph[V]then _6KCMph[V]={}end;for y,QF in kyWtqIf0(E3)do +S1wg_DG.all(AVFi,function(m403CY)return +S1wg_DG.include(m403CY,j6jQmlbr)end)then gWaGu[#gWaGu+1]=j6jQmlbr end end;return gWaGu end;function S1wg_DG.disjoint(...)return +(#S1wg_DG.intersection(...)==0)end +function S1wg_DG.symmetricDifference(dL,PrTsHeT)return +S1wg_DG.difference(S1wg_DG.union(dL,PrTsHeT),S1wg_DG.intersection(dL,PrTsHeT))end +function S1wg_DG.unique(eNI3MT7)local Rfoo={}for eUJhGD=1,#eNI3MT7 do if -QF[V]then _6KCMph[V][#_6KCMph[V]+1]=QF[V]end end end;return _6KCMph end -function S1wg_DG.zipWith(hN,...)local hVflx4kh={...} -local GP=S1wg_DG.max(hVflx4kh,function(RLaqM3)return#RLaqM3 end)local oCZYv2dT={}for PoH=1,GP do -oCZYv2dT[PoH]=hN(hUL(S1wg_DG.pluck(hVflx4kh,PoH)))end;return oCZYv2dT end -function S1wg_DG.append(xM709D,z50)local sAPD={} -for AVFi,GGKI in kyWtqIf0(xM709D)do sAPD[AVFi]=GGKI end;for gWaGu,SFKM in kyWtqIf0(z50)do sAPD[#sAPD+1]=SFKM end -return sAPD end -function S1wg_DG.interleave(...)local j6jQmlbr={...} -local m403CY=S1wg_DG.max(j6jQmlbr,S1wg_DG.size)local dL={} -for PrTsHeT=1,m403CY do for eNI3MT7,Rfoo in kyWtqIf0(j6jQmlbr)do -if Rfoo[PrTsHeT]then dL[#dL+1]=Rfoo[PrTsHeT]end end end;return dL end;function S1wg_DG.interpose(eUJhGD,wot8) -for j9vJ=#eUJhGD,2,-1 do odpE(eUJhGD,j9vJ,wot8)end;return eUJhGD end -function S1wg_DG.range(J6Qr27Mh,AwxW8Do,_u) +not S1wg_DG.find(Rfoo,eNI3MT7[eUJhGD])then Rfoo[#Rfoo+1]=eNI3MT7[eUJhGD]end end;return Rfoo end;function S1wg_DG.isunique(wot8)return +#wot8 ==# (S1wg_DG.unique(wot8))end +function S1wg_DG.duplicates(j9vJ) +local J6Qr27Mh=S1wg_DG.invert(j9vJ)local AwxW8Do={}for _u,B in kyWtqIf0(j9vJ)do +if J6Qr27Mh[B]~=_u and +not S1wg_DG.find(AwxW8Do,B)then AwxW8Do[#AwxW8Do+1]=B end end;return AwxW8Do end +function S1wg_DG.zip(...)local cdxFVpZw={...} +local Y=S1wg_DG.max(cdxFVpZw,function(BuX1r)return#BuX1r end)local o9Uh={} +for Wyf83f2=1,Y do if not o9Uh[Wyf83f2]then o9Uh[Wyf83f2]={}end +for P0olj,z in +kyWtqIf0(cdxFVpZw)do if z[Wyf83f2]then +o9Uh[Wyf83f2][#o9Uh[Wyf83f2]+1]=z[Wyf83f2]end end end;return o9Uh end +function S1wg_DG.zipWith(EHCCkt,...)local x={...} +local xNWVmS=S1wg_DG.max(x,function(Pkis6H28)return#Pkis6H28 end)local kGWnkgDu={}for tSE=1,xNWVmS do +kGWnkgDu[tSE]=EHCCkt(hUL(S1wg_DG.pluck(x,tSE)))end;return kGWnkgDu end +function S1wg_DG.append(abKH,LDp)local GWouUlzZ={} +for MqJhIr,Q9 in kyWtqIf0(abKH)do GWouUlzZ[MqJhIr]=Q9 end +for c,qnZ81I in kyWtqIf0(LDp)do GWouUlzZ[#GWouUlzZ+1]=qnZ81I end;return GWouUlzZ end +function S1wg_DG.interleave(...)local N9uN={...} +local QGC=S1wg_DG.max(N9uN,S1wg_DG.size)local K8iFU={} +for gbU=1,QGC do for h,hS7 in kyWtqIf0(N9uN)do +if hS7[gbU]then K8iFU[#K8iFU+1]=hS7[gbU]end end end;return K8iFU end;function S1wg_DG.interpose(KQjMKhN,R6PYgHHE) +for ZwCXrLO=#KQjMKhN,2,-1 do odpE(KQjMKhN,ZwCXrLO,R6PYgHHE)end;return KQjMKhN end +function S1wg_DG.range(lI,iMSMP5Lp,WoARZdZ3) if ( -J6Qr27Mh==nil)and(AwxW8Do==nil)and(_u==nil)then return{}elseif -(J6Qr27Mh~=nil)and(AwxW8Do==nil)and(_u==nil)then J6Qr27Mh,AwxW8Do,_u=Ub(J6Qr27Mh),J6Qr27Mh,Ub(J6Qr27Mh)elseif -(J6Qr27Mh~=nil)and(AwxW8Do~=nil)and(_u==nil)then _u=Ub(AwxW8Do- -J6Qr27Mh)end;local B={J6Qr27Mh} -local cdxFVpZw=BCf7(pS78Y((AwxW8Do-J6Qr27Mh)/_u),0)for Y=1,cdxFVpZw do B[#B+1]=J6Qr27Mh+_u*Y end;return B end;function S1wg_DG.rep(o9Uh,BuX1r)local Wyf83f2={}for P0olj=1,BuX1r do Wyf83f2[P0olj]=o9Uh end -return Wyf83f2 end -function S1wg_DG.powerset(z) -local EHCCkt=#z;if EHCCkt==0 then return{{}}end;local x={}for xNWVmS=1,EHCCkt do -for kGWnkgDu=1,EHCCkt-xNWVmS+1 do x[#x+1]=S1wg_DG.slice(z,kGWnkgDu, -kGWnkgDu+xNWVmS-1)end end;return x end;function S1wg_DG.partition(Pkis6H28,tSE,abKH)if tSE<=0 then return end +lI==nil)and(iMSMP5Lp==nil)and(WoARZdZ3 ==nil)then return{}elseif +(lI~=nil)and(iMSMP5Lp==nil)and(WoARZdZ3 ==nil)then lI,iMSMP5Lp,WoARZdZ3=Ub(lI),lI,Ub(lI)elseif +(lI~=nil)and(iMSMP5Lp~=nil)and(WoARZdZ3 ==nil)then +WoARZdZ3=Ub(iMSMP5Lp-lI)end;local n={lI} +local Uj=BCf7(pS78Y((iMSMP5Lp-lI)/WoARZdZ3),0)for HpN_N=1,Uj do n[#n+1]=lI+WoARZdZ3*HpN_N end;return n end +function S1wg_DG.rep(yP3QEJ,pwi)local QP={}for Iy=1,pwi do QP[Iy]=yP3QEJ end;return QP end +function S1wg_DG.powerset(O9P0mj)local eFGwPxi=#O9P0mj;if eFGwPxi==0 then return{{}}end;local m4x8ZsD4={}for _witc0Pe=1,eFGwPxi do +for Y8E=1, +eFGwPxi-_witc0Pe+1 do m4x8ZsD4[#m4x8ZsD4+1]=S1wg_DG.slice(O9P0mj,Y8E, +Y8E+_witc0Pe-1)end end +return m4x8ZsD4 end;function S1wg_DG.partition(h,EnMMG,HzO7UpZ)if EnMMG<=0 then return end return OV7(function() -MGSnnzOI(Pkis6H28,tSE or 1,X83a,abKH)end)end;function S1wg_DG.overlapping(LDp,GWouUlzZ,MqJhIr)if -GWouUlzZ<=1 then return end -return OV7(function() -B0o5xpg7(LDp,GWouUlzZ or 2,X83a,MqJhIr)end)end;function S1wg_DG.aperture(Q9,c)if -c<=1 then return end;return -OV7(function()VQT(Q9,c or 2,X83a)end)end;function S1wg_DG.pairwise(qnZ81I)return -S1wg_DG.aperture(qnZ81I,2)end -function S1wg_DG.permutation(N9uN)return OV7(function() -Id(N9uN,#N9uN,X83a)end)end;function S1wg_DG.invert(QGC)local K8iFU={}for gbU,h in kyWtqIf0(QGC)do K8iFU[h]=gbU end -return K8iFU end -function S1wg_DG.concat(hS7,KQjMKhN,R6PYgHHE,ZwCXrLO)return -JdUtcU(S1wg_DG.map(hS7,tostring),KQjMKhN,R6PYgHHE,ZwCXrLO)end -function S1wg_DG.xprod(lI,iMSMP5Lp)local WoARZdZ3={} -for n,Uj in kyWtqIf0(lI)do for HpN_N,yP3QEJ in kyWtqIf0(iMSMP5Lp)do -WoARZdZ3[#WoARZdZ3+1]={Uj,yP3QEJ}end end;return WoARZdZ3 end -function S1wg_DG.sum(pwi)local QP=0;for Iy,O9P0mj in kyWtqIf0(pwi)do QP=QP+O9P0mj end;return QP end -function S1wg_DG.product(eFGwPxi)local m4x8ZsD4=1 -for _witc0Pe,Y8E in kyWtqIf0(eFGwPxi)do m4x8ZsD4=m4x8ZsD4*Y8E end;return m4x8ZsD4 end -function S1wg_DG.mean(h)return S1wg_DG.sum(h)/ (#h)end -function S1wg_DG.median(EnMMG) -local HzO7UpZ=S1wg_DG.sort(S1wg_DG.clone(EnMMG))local B=#HzO7UpZ;if B==0 then return elseif B==1 then return HzO7UpZ[1]end -local RNTu=VCD(B/2) -return B%2 ==0 and -(HzO7UpZ[RNTu]+HzO7UpZ[RNTu+1])/2 or HzO7UpZ[RNTu]end;function S1wg_DG.noop()return end;function S1wg_DG.identity(Q_)return Q_ end;function S1wg_DG.constant(S8GB)return function()return -S8GB end end -function S1wg_DG.applySpec(W7yjGm)return -function(...) -local X={}for Y,qqvEf3 in l(W7yjGm)do X[Y]=qqvEf3(...)end;return X end end -function S1wg_DG.memoize(Wriu)local I0Pxr5F=oUA({},{__mode='kv'}) -return function(ukGf_)if -(I0Pxr5F[ukGf_]==nil)then I0Pxr5F[ukGf_]=Wriu(ukGf_)end;return -I0Pxr5F[ukGf_]end end -function S1wg_DG.unfold(uZpt01P,hJk0n8bR)local o9DTTJig,v4={} -while true do v4,hJk0n8bR=uZpt01P(hJk0n8bR)if v4 ~=nil then o9DTTJig[ -#o9DTTJig+1]=v4 else break end end;return o9DTTJig end -function S1wg_DG.once(Uaq2_Xzk)local S0DM=0;local GHasi5={} -return function(...)S0DM=S0DM+1;if S0DM<=1 then GHasi5={...}end;return -Uaq2_Xzk(hUL(GHasi5))end end -function S1wg_DG.before(QeX_U9tm,hgW2H5)local Dp9m=0;local sJjNM={}return -function(...)Dp9m=Dp9m+1 -if Dp9m<=hgW2H5 then sJjNM={...}end;return QeX_U9tm(hUL(sJjNM))end end -function S1wg_DG.after(GnSs,hgW2H5)local XP,Sj=hgW2H5,0;return -function(...)Sj=Sj+1;if Sj>=XP then return GnSs(...)end end end -function S1wg_DG.compose(...)local yKj1=S1wg_DG.reverse{...} +MGSnnzOI(h,EnMMG or 1,X83a,HzO7UpZ)end)end +function S1wg_DG.overlapping(B,RNTu,Q_)if +RNTu<=1 then return end;return +OV7(function()B0o5xpg7(B,RNTu or 2,X83a,Q_)end)end +function S1wg_DG.aperture(S8GB,W7yjGm)if W7yjGm<=1 then return end;return OV7(function() +VQT(S8GB,W7yjGm or 2,X83a)end)end +function S1wg_DG.pairwise(X)return S1wg_DG.aperture(X,2)end;function S1wg_DG.permutation(Y) +return OV7(function()Id(Y,#Y,X83a)end)end +function S1wg_DG.concat(qqvEf3,Wriu,I0Pxr5F,ukGf_)return +JdUtcU(S1wg_DG.map(qqvEf3,tostring),Wriu,I0Pxr5F,ukGf_)end +function S1wg_DG.xprod(uZpt01P,hJk0n8bR)local o9DTTJig={} +for v4,Uaq2_Xzk in kyWtqIf0(uZpt01P)do for S0DM,GHasi5 in kyWtqIf0(hJk0n8bR)do +o9DTTJig[#o9DTTJig+1]={Uaq2_Xzk,GHasi5}end end;return o9DTTJig end;function S1wg_DG.xpairs(QeX_U9tm,Dp9m)local sJjNM={} +for GnSs,XP in kyWtqIf0(Dp9m)do sJjNM[GnSs]={QeX_U9tm,XP}end;return sJjNM end +function S1wg_DG.xpairsRight(Sj,yKj1) +local F9WZ={}for A5,nY_O in kyWtqIf0(yKj1)do F9WZ[A5]={nY_O,Sj}end;return F9WZ end +function S1wg_DG.sum(QAJAyj5)local EZ=0;for n,M in kyWtqIf0(QAJAyj5)do EZ=EZ+M end;return EZ end;function S1wg_DG.product(AADiL1)local Arw=1 +for b,_ZM1Yj3 in kyWtqIf0(AADiL1)do Arw=Arw*_ZM1Yj3 end;return Arw end;function S1wg_DG.mean(rmSU)return +S1wg_DG.sum(rmSU)/ (#rmSU)end +function S1wg_DG.median(L2RHrI) +local XW7Y5Rz=S1wg_DG.sort(S1wg_DG.clone(L2RHrI))local C=#XW7Y5Rz;if C==0 then return elseif C==1 then return XW7Y5Rz[1]end +local NhwEkTd=VCD(C/2)return +C%2 ==0 and +(XW7Y5Rz[NhwEkTd]+XW7Y5Rz[NhwEkTd+1])/2 or XW7Y5Rz[NhwEkTd]end;function S1wg_DG.noop()return end;function S1wg_DG.identity(XGz)return XGz end;function S1wg_DG.call(Tf4P2eIf,...)return +Tf4P2eIf(...)end;function S1wg_DG.constant(TF3Htu) +return function()return TF3Htu end end +function S1wg_DG.applySpec(K5yUw1t)return +function(...)local Mi={}for WWyrqnSL,gVTyP in l(K5yUw1t)do +Mi[WWyrqnSL]=gVTyP(...)end;return Mi end end +function S1wg_DG.thread(Ck,...)local CRG=Ck;local dkz={...} +for zrCq,azXMvVdM in kyWtqIf0(dkz)do +if v(azXMvVdM)=='function'then +CRG=azXMvVdM(CRG)elseif v(azXMvVdM)=='table'then local CBgxHfbq=azXMvVdM[1]lIpFkbLI(azXMvVdM,1) +CRG=S1wg_DG.reduce(azXMvVdM,CBgxHfbq,CRG)end end;return CRG end +function S1wg_DG.threadRight(WO,...)local H=WO;local C28NuJ3={...} +for sz,qH in kyWtqIf0(C28NuJ3)do if v(qH)=='function'then H=qH(H)elseif +v(qH)=='table'then local u=qH[1]lIpFkbLI(qH,1)odpE(qH,H) +H=S1wg_DG.reduce(qH,u)end end;return H end +function S1wg_DG.dispatch(...)local u={...}return +function(...)for J1Vn4uYP,Z in kyWtqIf0(u)do local pJ={Z(...)} +if#pJ>0 then return hUL(pJ)end end end end;function S1wg_DG.memoize(NAjg)local con=oUA({},{__mode='kv'}) +return function(I)if(con[I]==nil)then +con[I]=NAjg(I)end;return con[I]end end +function S1wg_DG.unfold(TxmZR6UE,I1b4o) +local nAt,pNJ={}while true do pNJ,I1b4o=TxmZR6UE(I1b4o) +if pNJ~=nil then nAt[#nAt+1]=pNJ else break end end;return nAt end +function S1wg_DG.once(RQ)local wnZcHKf=0;local Lv_8={} +return function(...)wnZcHKf=wnZcHKf+1 +if wnZcHKf<=1 then Lv_8={...}end;return RQ(hUL(Lv_8))end end +function S1wg_DG.before(UQ,hgW2H5)local FG=0;local vLzqjJw={} +return function(...)FG=FG+1;if FG<=hgW2H5 then vLzqjJw={...}end;return +UQ(hUL(vLzqjJw))end end +function S1wg_DG.after(v2dsC21,hgW2H5)local O,wx=hgW2H5,0;return +function(...)wx=wx+1;if wx>=O then return v2dsC21(...)end end end +function S1wg_DG.compose(...)local u=S1wg_DG.reverse{...} return -function(...)local F9WZ,A5=true;for nY_O,QAJAyj5 in -kyWtqIf0(yKj1)do -if F9WZ then F9WZ=false;A5=QAJAyj5(...)else A5=QAJAyj5(A5)end end;return A5 end end -function S1wg_DG.pipe(EZ,...)return S1wg_DG.compose(...)(EZ)end -function S1wg_DG.complement(n)return function(...)return not n(...)end end -function S1wg_DG.juxtapose(M,...)local AADiL1={} -for Arw,b in kyWtqIf0({...})do AADiL1[Arw]=b(M)end;return hUL(AADiL1)end;function S1wg_DG.wrap(_ZM1Yj3,rmSU) -return function(...)return rmSU(_ZM1Yj3,...)end end;function S1wg_DG.times(L2RHrI,XW7Y5Rz,...)local C={}for NhwEkTd=1,(XW7Y5Rz or 1) -do C[NhwEkTd]=L2RHrI(NhwEkTd,...)end -return C end -function S1wg_DG.bind(XGz,Tf4P2eIf)return function(...)return -XGz(Tf4P2eIf,...)end end;function S1wg_DG.bind2(TF3Htu,K5yUw1t) -return function(Mi,...)return TF3Htu(Mi,K5yUw1t,...)end end;function S1wg_DG.bindn(WWyrqnSL,...)local gVTyP={...} +function(...)local V_84V,qF=true +for IZbOX7TW,Dd6ZLpU in kyWtqIf0(u)do if V_84V then +V_84V=false;qF=Dd6ZLpU(...)else qF=Dd6ZLpU(qF)end end;return qF end end +function S1wg_DG.pipe(MP,...)return S1wg_DG.compose(...)(MP)end +function S1wg_DG.complement(w4c)return function(...)return not w4c(...)end end +function S1wg_DG.juxtapose(C58,...)local Jk6Nh={} +for s1Ws,desLYv in kyWtqIf0({...})do Jk6Nh[s1Ws]=desLYv(C58)end;return hUL(Jk6Nh)end;function S1wg_DG.wrap(COq2NY9I,aoBEg65S) +return function(...)return aoBEg65S(COq2NY9I,...)end end +function S1wg_DG.times(x6,t3cNa2l)local Ik={}for SeHOs=1,(t3cNa2l or 1) +do Ik[SeHOs]=x6(SeHOs)end;return Ik end +function S1wg_DG.bind(P2rGsUx,c)return function(...)return P2rGsUx(c,...)end end;function S1wg_DG.bind2(v12AhMm,F2uxGC) +return function(Xs0,...)return v12AhMm(Xs0,F2uxGC,...)end end;function S1wg_DG.bindn(QK8ibF,...)local TEio7k0z={...} return function(...)return -WWyrqnSL(hUL(S1wg_DG.append(gVTyP,{...})))end end -function S1wg_DG.bindall(Ck,...) -local CRG={...} -for dkz,zrCq in kyWtqIf0(CRG)do local azXMvVdM=Ck[zrCq]if azXMvVdM then -Ck[zrCq]=S1wg_DG.bind(azXMvVdM,Ck)end end;return Ck end;function S1wg_DG.cond(CBgxHfbq) +QK8ibF(hUL(S1wg_DG.append(TEio7k0z,{...})))end end +function S1wg_DG.bindall(u,...) +local N={...}for O2YgxDc,VLsC67 in kyWtqIf0(N)do local OHw4=u[VLsC67] +if OHw4 then u[VLsC67]=S1wg_DG.bind(OHw4,u)end end;return u end +function S1wg_DG.cond(FKZ)return +function(...)for Fl,QhS8FvKI in kyWtqIf0(FKZ)do +if QhS8FvKI[1](...)then return QhS8FvKI[2](...)end end end end +function S1wg_DG.both(...)local FaZIJL={...} return function(...) -for WO,H in kyWtqIf0(CBgxHfbq)do if H[1](...)then return H[2](...)end end end end -function S1wg_DG.uniqueId(C28NuJ3,...)qJExeUn2= -qJExeUn2+1;if C28NuJ3 then -if v(C28NuJ3)=='string'then -return C28NuJ3:format(qJExeUn2)elseif v(C28NuJ3)=='function'then return C28NuJ3(qJExeUn2,...)end end;return -qJExeUn2 end -function S1wg_DG.iterator(sz,qH,u)local uJ1Vn4uYP=0 -return function()uJ1Vn4uYP=uJ1Vn4uYP+1 -if u and uJ1Vn4uYP>u then return end;qH=sz(qH)return qH end end -function S1wg_DG.array(...)local Z={}for pJ in...do Z[#Z+1]=pJ end;return Z end;function S1wg_DG.castArray(NAjg)return -(v(NAjg)~='table')and{NAjg}or NAjg end;function S1wg_DG.flip(con) -return function(...)return -con(hUL(S1wg_DG.reverse({...})))end end;function S1wg_DG.nthArg(I) -return function(...)local TxmZR6UE={...}return -TxmZR6UE[( -I<0)and(#TxmZR6UE+I+1)or I]end end;function S1wg_DG.unary(I1b4o) +for sOT2O5,x in kyWtqIf0(FaZIJL)do if not x(...)then return false end end;return true end end +function S1wg_DG.either(...)local Wswd_OC={...} return function(...) -local nAt={...}return I1b4o(nAt[1])end end -function S1wg_DG.ary(pNJ,RQ)RQ=RQ or 1 +for E,A0Un in kyWtqIf0(Wswd_OC)do if A0Un(...)then return true end end;return false end end +function S1wg_DG.neither(...)local nRHrI={...} return function(...) -local wnZcHKf={...}local Lv_8={}for UQ=1,RQ do Lv_8[UQ]=wnZcHKf[UQ]end -return pNJ(hUL(Lv_8))end end -function S1wg_DG.rearg(FG,vLzqjJw)return -function(...)local v2dsC21={...}local O={} -for wx,u in kyWtqIf0(vLzqjJw)do O[wx]=v2dsC21[u]end;return FG(hUL(O))end end -function S1wg_DG.over(...)local V_84V={...}return -function(...)local qF={}for IZbOX7TW,Dd6ZLpU in kyWtqIf0(V_84V)do -qF[#qF+1]=Dd6ZLpU(...)end;return qF end end -function S1wg_DG.overEvery(...)local MP=S1wg_DG.over(...) +for kZp,A in kyWtqIf0(nRHrI)do if A(...)then return false end end;return true end end +function S1wg_DG.uniqueId(_L_)qJExeUn2=qJExeUn2+1;if _L_ then +if v(_L_)=='string'then +return _L_:format(qJExeUn2)elseif v(_L_)=='function'then return _L_(qJExeUn2)end end;return qJExeUn2 end +function S1wg_DG.iterator(WHpm,g,HiR3yiw)local KeKbiDqN=0;return +function()KeKbiDqN=KeKbiDqN+1;if +HiR3yiw and KeKbiDqN>HiR3yiw then return end;g=WHpm(g)return g end end;function S1wg_DG.skip(WfrZqHH8,YX9s9O) +for y64dF=1,(YX9s9O or 1)do if WfrZqHH8()==nil then return end end;return WfrZqHH8 end +function S1wg_DG.tabulate(...) +local sNSsH={}for K in...do sNSsH[#sNSsH+1]=K end;return sNSsH end +function S1wg_DG.iterlen(...)local o8T=0;for xeP in...do o8T=o8T+1 end;return o8T end +function S1wg_DG.castArray(Tv_3VlmX)return(v(Tv_3VlmX)~='table')and{Tv_3VlmX}or +Tv_3VlmX end +function S1wg_DG.flip(BT)return function(...) +return BT(hUL(S1wg_DG.reverse({...})))end end;function S1wg_DG.nthArg(_y3z) +return function(...)local rdl={...}return +rdl[(_y3z<0)and(#rdl+_y3z+1)or _y3z]end end;function S1wg_DG.unary(NAP_5jYs) return function(...) -return S1wg_DG.reduce(MP(...),function(w4c,C58) -return w4c and C58 end)end end -function S1wg_DG.overSome(...)local Jk6Nh=S1wg_DG.over(...) +local BZnlpW={...}return NAP_5jYs(BZnlpW[1])end end +function S1wg_DG.ary(isN,yRADzw1v) +yRADzw1v=yRADzw1v or 1;return +function(...)local Jafp={...}local XWh8Ee={} +for kpezL1e=1,yRADzw1v do XWh8Ee[kpezL1e]=Jafp[kpezL1e]end;return isN(hUL(XWh8Ee))end end;function S1wg_DG.noarg(h)return function()return h()end end +function S1wg_DG.rearg(R7yfz_l9,D35PFLu) +return +function(...) +local wK={...}local qeEwE={} +for cbtvFnSa,fYKH_ in kyWtqIf0(D35PFLu)do qeEwE[cbtvFnSa]=wK[fYKH_]end;return R7yfz_l9(hUL(qeEwE))end end;function S1wg_DG.over(...)local W={...} +return function(...)local o={} +for Mm99M,l6YH in kyWtqIf0(W)do o[#o+1]=l6YH(...)end;return o end end +function S1wg_DG.overEvery(...) +local gf2=S1wg_DG.over(...)return +function(...)return +S1wg_DG.reduce(gf2(...),function(F744Ew,zgxKF4)return F744Ew and zgxKF4 end)end end +function S1wg_DG.overSome(...)local UlvVvSBR=S1wg_DG.over(...) return function(...) -return S1wg_DG.reduce(Jk6Nh(...),function(s1Ws,desLYv)return -s1Ws or desLYv end)end end -function S1wg_DG.overArgs(COq2NY9I,...)local aoBEg65S={...} +return S1wg_DG.reduce(UlvVvSBR(...),function(i2i,uRGAL)return +i2i or uRGAL end)end end +function S1wg_DG.overArgs(UUlqXyb6,...)local fOR92g8={...} return -function(...)local x6={...} -for t3cNa2l=1,#aoBEg65S do local Ik=aoBEg65S[t3cNa2l]if -x6[t3cNa2l]then x6[t3cNa2l]=Ik(x6[t3cNa2l])end end;return COq2NY9I(hUL(x6))end end -function S1wg_DG.converge(SeHOs,P2rGsUx,c)return -function(...)return SeHOs(P2rGsUx(...),c(...))end end -function S1wg_DG.partial(v12AhMm,...)local F2uxGC={...} +function(...)local jU26={...}for WIPTsAPz=1,#fOR92g8 do +local DgUx8=fOR92g8[WIPTsAPz] +if jU26[WIPTsAPz]then jU26[WIPTsAPz]=DgUx8(jU26[WIPTsAPz])end end;return +UUlqXyb6(hUL(jU26))end end +function S1wg_DG.converge(imac,xX,Mfb6Kb)return +function(...)return imac(xX(...),Mfb6Kb(...))end end +function S1wg_DG.partial(RRjV,...)local TDOaFo={...} return -function(...)local Xs0={...}local QK8ibF={}for TEio7k0z,u in kyWtqIf0(F2uxGC)do -QK8ibF[TEio7k0z]=(u== -'_')and S1wg_DG.shift(Xs0)or u end;return -v12AhMm(hUL(S1wg_DG.append(QK8ibF,Xs0)))end end -function S1wg_DG.partialRight(N,...)local O2YgxDc={...} +function(...)local tLo4={...}local m72l={}for npM3DSU,HGp4e1 in kyWtqIf0(TDOaFo)do +m72l[npM3DSU]= +(HGp4e1 =='_')and S1wg_DG.shift(tLo4)or HGp4e1 end;return +RRjV(hUL(S1wg_DG.append(m72l,tLo4)))end end +function S1wg_DG.partialRight(uzJt7E,...)local sRe5S32N={...} return -function(...)local VLsC67={...}local OHw4={} -for FKZ=1,#O2YgxDc do OHw4[FKZ]=(O2YgxDc[FKZ]== -'_')and S1wg_DG.shift(VLsC67)or -O2YgxDc[FKZ]end -return N(hUL(S1wg_DG.append(VLsC67,OHw4)))end end -function S1wg_DG.curry(Fl,QhS8FvKI)QhS8FvKI=QhS8FvKI or 2;local FaZIJL={} -local function sOT2O5(x) -if QhS8FvKI==1 then return Fl(x)end;if x~=nil then FaZIJL[#FaZIJL+1]=x end;if -#FaZIJL<QhS8FvKI then return sOT2O5 else local Wswd_OC={Fl(hUL(FaZIJL))}FaZIJL={} -return hUL(Wswd_OC)end end;return sOT2O5 end -function S1wg_DG.time(E,...)local A0Un=Mw()local nRHrI={E(...)}return Mw()-A0Un,hUL(nRHrI)end -function S1wg_DG.keys(k)local Zp={}for A in l(k)do Zp[#Zp+1]=A end;return Zp end;function S1wg_DG.values(_L_)local WHpm={} -for g,HiR3yiw in l(_L_)do WHpm[#WHpm+1]=HiR3yiw end;return WHpm end -function S1wg_DG.path(KeKbiDqN,...) -local WfrZqHH8,YX9s9O=KeKbiDqN,{...}for y64dF,sNSsH in kyWtqIf0(YX9s9O)do if(WfrZqHH8[sNSsH]==nil)then return end -WfrZqHH8=WfrZqHH8[sNSsH]end;return WfrZqHH8 end;function S1wg_DG.kvpairs(K)local o8T={} -for xeP,Tv_3VlmX in l(K)do o8T[#o8T+1]={xeP,Tv_3VlmX}end;return o8T end;function S1wg_DG.toObj(BT) -local _y3z={} -for rdl,NAP_5jYs in kyWtqIf0(BT)do _y3z[NAP_5jYs[1]]=NAP_5jYs[2]end;return _y3z end -function S1wg_DG.property(BZnlpW)return function(isN)return -isN[BZnlpW]end end;function S1wg_DG.propertyOf(yRADzw1v) -return function(Jafp)return yRADzw1v[Jafp]end end;function S1wg_DG.toBoolean(XWh8Ee) -return not not XWh8Ee end -function S1wg_DG.extend(kpezL1e,...)local h={...}for R7yfz_l9,D35PFLu in kyWtqIf0(h)do +function(...)local Bp={...}local rg={}for S=1,#sRe5S32N do +rg[S]= +(sRe5S32N[S]=='_')and S1wg_DG.shift(Bp)or sRe5S32N[S]end;return +uzJt7E(hUL(S1wg_DG.append(Bp,rg)))end end +function S1wg_DG.curry(Fem,cHmVGY)cHmVGY=cHmVGY or 2;local g29sXR={} +local function Vat(sfnkWAy8) +if cHmVGY==1 then return Fem(sfnkWAy8)end +if sfnkWAy8 ~=nil then g29sXR[#g29sXR+1]=sfnkWAy8 end;if#g29sXR<cHmVGY then return Vat else local hbJSGe9={Fem(hUL(g29sXR))} +g29sXR={}return hUL(hbJSGe9)end end;return Vat end +function S1wg_DG.time(pI,...)local B7jhm=Mw()local hj3={pI(...)}return Mw()-B7jhm,hUL(hj3)end +function S1wg_DG.keys(FKxU4)local UW={}for tReY in l(FKxU4)do UW[#UW+1]=tReY end;return UW end;function S1wg_DG.values(lex)local h79Pm={} +for vksQpy4,gPCIWPt in l(lex)do h79Pm[#h79Pm+1]=gPCIWPt end;return h79Pm end +function S1wg_DG.path(l4Byxa7,...) +local Fn8OR,X1Z0van=l4Byxa7,{...}for C_ACFsd,GC in kyWtqIf0(X1Z0van)do if(Fn8OR[GC]==nil)then return end +Fn8OR=Fn8OR[GC]end;return Fn8OR end +function S1wg_DG.spreadPath(SC7gSvMB,...)local Ei={...} +for GFuK1ut,SXmRY3i in kyWtqIf0(Ei)do if SC7gSvMB[SXmRY3i]then +for b,KApFr in +l(SC7gSvMB[SXmRY3i])do SC7gSvMB[b]=KApFr;SC7gSvMB[SXmRY3i][b]=nil end end end;return SC7gSvMB end +function S1wg_DG.flattenPath(jE,...)local yVVmXC={...} +for MkxwoCeK,AT in kyWtqIf0(yVVmXC)do if jE[AT]then +for _8KO,NI in l(jE[AT])do jE[_8KO]=NI end end end;return jE end;function S1wg_DG.kvpairs(PE)local a={} +for GhVWeuQs,kQlY in l(PE)do a[#a+1]={GhVWeuQs,kQlY}end;return a end +function S1wg_DG.toObj(xIl1shq)local qv={}for pbEt6T,MBdHQ in +kyWtqIf0(xIl1shq)do qv[MBdHQ[1]]=MBdHQ[2]end;return qv end;function S1wg_DG.invert(STXAhhM)local assFn={}for EXpWzv,kq in l(STXAhhM)do assFn[kq]=EXpWzv end +return assFn end +function S1wg_DG.property(up)return function(wlI_l)return +wlI_l[up]end end +function S1wg_DG.propertyOf(nK7J)return function(xv)return nK7J[xv]end end;function S1wg_DG.toBoolean(IWG)return not not IWG end +function S1wg_DG.extend(XVipkEh,...) +local Y_xg20={...} +for lOn,Mn29lGrm in kyWtqIf0(Y_xg20)do if v(Mn29lGrm)=='table'then +for y,ye3DyN in l(Mn29lGrm)do XVipkEh[y]=ye3DyN end end end;return XVipkEh end +function S1wg_DG.functions(XoIfNq,zCZ)XoIfNq=XoIfNq or S1wg_DG;local KOblE1BH={} +for YPFM2F,iA in l(XoIfNq)do if +v(iA)=='function'then KOblE1BH[#KOblE1BH+1]=YPFM2F end end +if zCZ then local f=QFKEzBf(XoIfNq)if f and f.__index then +local W=S1wg_DG.functions(f.__index,zCZ) +for _,_TPK9KUS in kyWtqIf0(W)do KOblE1BH[#KOblE1BH+1]=_TPK9KUS end end end;return KOblE1BH end +function S1wg_DG.clone(CcTDi,HNz)if v(CcTDi)~='table'then return CcTDi end;local _T9Gn3b2={}for mx,X in l(CcTDi)do if -v(D35PFLu)=='table'then for wK,qeEwE in l(D35PFLu)do kpezL1e[wK]=qeEwE end end end;return kpezL1e end -function S1wg_DG.functions(cbtvFnSa,fYKH_)cbtvFnSa=cbtvFnSa or S1wg_DG;local W={}for o,Mm99M in l(cbtvFnSa)do if -v(Mm99M)=='function'then W[#W+1]=o end end -if fYKH_ then -local l6YH=QFKEzBf(cbtvFnSa) -if l6YH and l6YH.__index then -local gf2=S1wg_DG.functions(l6YH.__index,fYKH_)for F744Ew,zgxKF4 in kyWtqIf0(gf2)do W[#W+1]=zgxKF4 end end end;return W end -function S1wg_DG.clone(UlvVvSBR,i2i)if v(UlvVvSBR)~='table'then return UlvVvSBR end -local uRGAL={} -for UUlqXyb6,fOR92g8 in l(UlvVvSBR)do if v(fOR92g8)=='table'then if not i2i then -uRGAL[UUlqXyb6]=S1wg_DG.clone(fOR92g8,i2i)else uRGAL[UUlqXyb6]=fOR92g8 end else -uRGAL[UUlqXyb6]=fOR92g8 end end;return uRGAL end -function S1wg_DG.tap(jU26,WIPTsAPz,...)WIPTsAPz(jU26,...)return jU26 end;function S1wg_DG.has(DgUx8,imac)return DgUx8[imac]~=nil end -function S1wg_DG.pick(xX,...) -local Mfb6Kb=S1wg_DG.flatten{...}local RRjV={}for TDOaFo,tLo4 in l(Mfb6Kb)do -if(xX[tLo4])~=nil then RRjV[tLo4]=xX[tLo4]end end;return RRjV end -function S1wg_DG.omit(m72l,...)local npM3DSU=S1wg_DG.flatten{...}local HGp4e1={}for uzJt7E,sRe5S32N in l(m72l)do -if not -S1wg_DG.include(npM3DSU,uzJt7E)then HGp4e1[uzJt7E]=sRe5S32N end end;return HGp4e1 end;function S1wg_DG.template(Bp,rg)if not rg then return Bp end -for S,Fem in l(rg)do if not Bp[S]then Bp[S]=Fem end end;return Bp end -function S1wg_DG.isEqual(cHmVGY,g29sXR,Vat) -local sfnkWAy8=v(cHmVGY)local hbJSGe9=v(g29sXR)if sfnkWAy8 ~=hbJSGe9 then return false end;if -sfnkWAy8 ~='table'then return(cHmVGY==g29sXR)end -local pI=QFKEzBf(cHmVGY)local B7jhm=QFKEzBf(g29sXR) -if Vat then if(pI or B7jhm)and -(pI.__eq or B7jhm.__eq)then -return -pI.__eq(cHmVGY,g29sXR)or B7jhm.__eq(g29sXR,cHmVGY)or(cHmVGY==g29sXR)end end -if S1wg_DG.size(cHmVGY)~=S1wg_DG.size(g29sXR)then return false end;local hj3 -for FKxU4,UW in l(cHmVGY)do hj3=g29sXR[FKxU4]if hj3 ==nil or -not S1wg_DG.isEqual(UW,hj3,Vat)then return false end end -for tReY in l(g29sXR)do if cHmVGY[tReY]==nil then return false end end;return true end -function S1wg_DG.result(lex,h79Pm,...) -if lex[h79Pm]then if S1wg_DG.isCallable(lex[h79Pm])then return -lex[h79Pm](lex,...)else return lex[h79Pm]end end -if S1wg_DG.isCallable(h79Pm)then return h79Pm(lex,...)end end -function S1wg_DG.isTable(vksQpy4)return v(vksQpy4)=='table'end -function S1wg_DG.isCallable(gPCIWPt)return +v(X)=='table'then if not HNz then _T9Gn3b2[mx]=S1wg_DG.clone(X,HNz)else +_T9Gn3b2[mx]=X end else _T9Gn3b2[mx]=X end end;return +_T9Gn3b2 end;function S1wg_DG.tap(j,hwLm)hwLm(j)return j end;function S1wg_DG.has(Jf1lygU,uCC)return +Jf1lygU[uCC]~=nil end +function S1wg_DG.pick(VoL,...) +local J1Qkmucu=S1wg_DG.flatten{...}local uy8VNDqE={} +for LCuIIfa,SUcXQMl in l(J1Qkmucu)do if(VoL[SUcXQMl])~=nil then +uy8VNDqE[SUcXQMl]=VoL[SUcXQMl]end end;return uy8VNDqE end +function S1wg_DG.omit(lyRouGA3,...)local Q3y7y2=S1wg_DG.flatten{...}local xPOK4sH={} +for Px1,SUg in l(lyRouGA3)do if not +S1wg_DG.include(Q3y7y2,Px1)then xPOK4sH[Px1]=SUg end end;return xPOK4sH end +function S1wg_DG.template(Wf0F6,G3)if not G3 then return Wf0F6 end;for D,Yghyekk in l(G3)do +if not Wf0F6[D]then Wf0F6[D]=Yghyekk end end;return Wf0F6 end +function S1wg_DG.isEqual(axo,Sv,aKiYWdc)local tSTVAx=v(axo)local E4dT34=v(Sv) +if tSTVAx~=E4dT34 then return false end;if tSTVAx~='table'then return(axo==Sv)end;local L0=QFKEzBf(axo) +local wY=QFKEzBf(Sv)if aKiYWdc then +if(L0 or wY)and(L0.__eq or wY.__eq)then return L0.__eq(axo,Sv)or +wY.__eq(Sv,axo)or(axo==Sv)end end;if +S1wg_DG.size(axo)~=S1wg_DG.size(Sv)then return false end +local ilY2;for oe1We,jQLYx1y in l(axo)do ilY2=Sv[oe1We] +if ilY2 ==nil or +not S1wg_DG.isEqual(jQLYx1y,ilY2,aKiYWdc)then return false end end;for m_zjn in l(Sv)do if +axo[m_zjn]==nil then return false end end +return true end +function S1wg_DG.result(TyjL,JVvqdW4)if TyjL[JVvqdW4]then +if S1wg_DG.isCallable(TyjL[JVvqdW4])then return +TyjL[JVvqdW4](TyjL)else return TyjL[JVvqdW4]end end;if +S1wg_DG.isCallable(JVvqdW4)then return JVvqdW4(TyjL)end end;function S1wg_DG.isTable(kDuC)return v(kDuC)=='table'end +function S1wg_DG.isCallable(AUw)return +(( +v(AUw)=='function')or ( -(v(gPCIWPt)=='function')or( -(v(gPCIWPt)=='table')and QFKEzBf(gPCIWPt)and -QFKEzBf(gPCIWPt).__call~=nil)or false)end -function S1wg_DG.isArray(l4Byxa7) -if not(v(l4Byxa7)=='table')then return false end;local Fn8OR=0;for X1Z0van in l(l4Byxa7)do Fn8OR=Fn8OR+1 -if l4Byxa7[Fn8OR]==nil then return false end end;return true end;function S1wg_DG.isIterable(C_ACFsd) -return S1wg_DG.toBoolean((l6Sm5(l,C_ACFsd)))end -function S1wg_DG.isEmpty(GC) -if(GC==nil)then return true end;if v(GC)=='string'then return#GC==0 end;if v(GC)=='table'then -return e(GC)==nil end;return true end -function S1wg_DG.isString(SC7gSvMB)return v(SC7gSvMB)=='string'end;function S1wg_DG.isFunction(Ei)return v(Ei)=='function'end;function S1wg_DG.isNil(GFuK1ut)return -GFuK1ut==nil end;function S1wg_DG.isNumber(SXmRY3i)return -v(SXmRY3i)=='number'end;function S1wg_DG.isNaN(b)return -v(b)=='number'and b~=b end;function S1wg_DG.isFinite(KApFr)if v(KApFr)~='number'then return +(v(AUw)=='table')and QFKEzBf(AUw)and QFKEzBf(AUw).__call~=nil)or false)end +function S1wg_DG.isArray(vCkLg) +if not(v(vCkLg)=='table')then return false end;local A3mjn=0;for Wt5k in l(vCkLg)do A3mjn=A3mjn+1 +if vCkLg[A3mjn]==nil then return false end end;return true end;function S1wg_DG.isIterable(fv5Y2j) +return S1wg_DG.toBoolean((l6Sm5(l,fv5Y2j)))end +function S1wg_DG.type(bSgv)local Wa5=v(bSgv)if +Wa5 =='userdata'then local JyrC7=QFKEzBf(bSgv) +if JyrC7 ==QFKEzBf(io.stdout)then return'file'end end;return Wa5 end +function S1wg_DG.isEmpty(QP)if(QP==nil)then return true end +if v(QP)=='string'then return#QP==0 end;if v(QP)=='table'then return e(QP)==nil end;return true end;function S1wg_DG.isString(_N)return v(_N)=='string'end;function S1wg_DG.isFunction(U)return +v(U)=='function'end;function S1wg_DG.isNil(e5qv6Q) +return e5qv6Q==nil end +function S1wg_DG.isNumber(S6XO)return v(S6XO)=='number'end;function S1wg_DG.isNaN(p7ogY) +return v(p7ogY)=='number'and p7ogY~=p7ogY end;function S1wg_DG.isFinite(ZDP5SDwL)if v(ZDP5SDwL)~='number'then return false end -return KApFr>-S9TO and KApFr<S9TO end;function S1wg_DG.isBoolean(jE)return v(jE)== -'boolean'end -function S1wg_DG.isInteger(yVVmXC)return -v(yVVmXC)=='number'and pS78Y(yVVmXC)==yVVmXC end -do S1wg_DG.forEach=S1wg_DG.each;S1wg_DG.forEachi=S1wg_DG.eachi -S1wg_DG.update=S1wg_DG.adjust;S1wg_DG.loop=S1wg_DG.cycle;S1wg_DG.collect=S1wg_DG.map +return ZDP5SDwL>-S9TO and ZDP5SDwL<S9TO end;function S1wg_DG.isBoolean(T7H)return +v(T7H)=='boolean'end;function S1wg_DG.isInteger(cdPmXFla) +return +v(cdPmXFla)=='number'and pS78Y(cdPmXFla)==cdPmXFla end +do +S1wg_DG.forEach=S1wg_DG.each;S1wg_DG.forEachi=S1wg_DG.eachi;S1wg_DG.update=S1wg_DG.adjust +S1wg_DG.alleq=S1wg_DG.allEqual;S1wg_DG.loop=S1wg_DG.cycle;S1wg_DG.collect=S1wg_DG.map S1wg_DG.inject=S1wg_DG.reduce;S1wg_DG.foldl=S1wg_DG.reduce S1wg_DG.injectr=S1wg_DG.reduceRight;S1wg_DG.foldr=S1wg_DG.reduceRight S1wg_DG.mapr=S1wg_DG.mapReduce;S1wg_DG.maprr=S1wg_DG.mapReduceRight @@ -476,36 +527,35 @@ S1wg_DG.filter=S1wg_DG.select;S1wg_DG.discard=S1wg_DG.reject;S1wg_DG.every=S1wg_ S1wg_DG.takeWhile=S1wg_DG.selectWhile;S1wg_DG.rejectWhile=S1wg_DG.dropWhile;S1wg_DG.pop=S1wg_DG.shift S1wg_DG.remove=S1wg_DG.pull;S1wg_DG.rmRange=S1wg_DG.removeRange S1wg_DG.chop=S1wg_DG.removeRange;S1wg_DG.sub=S1wg_DG.slice;S1wg_DG.head=S1wg_DG.first -S1wg_DG.take=S1wg_DG.first;S1wg_DG.tail=S1wg_DG.rest;S1wg_DG.skip=S1wg_DG.last -S1wg_DG.without=S1wg_DG.difference;S1wg_DG.diff=S1wg_DG.difference -S1wg_DG.symdiff=S1wg_DG.symmetricDifference;S1wg_DG.xor=S1wg_DG.symmetricDifference -S1wg_DG.uniq=S1wg_DG.unique;S1wg_DG.isuniq=S1wg_DG.isunique;S1wg_DG.transpose=S1wg_DG.zip -S1wg_DG.part=S1wg_DG.partition;S1wg_DG.perm=S1wg_DG.permutation +S1wg_DG.take=S1wg_DG.first;S1wg_DG.tail=S1wg_DG.rest;S1wg_DG.without=S1wg_DG.difference +S1wg_DG.diff=S1wg_DG.difference;S1wg_DG.symdiff=S1wg_DG.symmetricDifference +S1wg_DG.xor=S1wg_DG.symmetricDifference;S1wg_DG.uniq=S1wg_DG.unique;S1wg_DG.isuniq=S1wg_DG.isunique +S1wg_DG.transpose=S1wg_DG.zip;S1wg_DG.part=S1wg_DG.partition;S1wg_DG.perm=S1wg_DG.permutation S1wg_DG.transposeWith=S1wg_DG.zipWith;S1wg_DG.intersperse=S1wg_DG.interpose S1wg_DG.sliding=S1wg_DG.aperture;S1wg_DG.mirror=S1wg_DG.invert;S1wg_DG.join=S1wg_DG.concat S1wg_DG.average=S1wg_DG.mean;S1wg_DG.always=S1wg_DG.constant;S1wg_DG.cache=S1wg_DG.memoize S1wg_DG.juxt=S1wg_DG.juxtapose;S1wg_DG.uid=S1wg_DG.uniqueid;S1wg_DG.iter=S1wg_DG.iterator -S1wg_DG.tabulate=S1wg_DG.array;S1wg_DG.nAry=S1wg_DG.ary;S1wg_DG.methods=S1wg_DG.functions -S1wg_DG.choose=S1wg_DG.pick;S1wg_DG.drop=S1wg_DG.omit;S1wg_DG.defaults=S1wg_DG.template +S1wg_DG.nAry=S1wg_DG.ary;S1wg_DG.methods=S1wg_DG.functions;S1wg_DG.choose=S1wg_DG.pick +S1wg_DG.drop=S1wg_DG.omit;S1wg_DG.defaults=S1wg_DG.template S1wg_DG.compare=S1wg_DG.isEqual;S1wg_DG.matches=S1wg_DG.isEqual end -do local MkxwoCeK={}local AT={}AT.__index=MkxwoCeK;local function _8KO(NI) -return oUA({_value=NI,_wrapped=true},AT)end -oUA(AT,{__call=function(PE,a)return _8KO(a)end,__index=function(GhVWeuQs,kQlY,...)return -MkxwoCeK[kQlY]end})function AT.chain(xIl1shq)return _8KO(xIl1shq)end -function AT:value()return self._value end;MkxwoCeK.chain,MkxwoCeK.value=AT.chain,AT.value -for qv,pbEt6T in l(S1wg_DG)do +do local gOp2cWZ={}local A1={}A1.__index=gOp2cWZ;local function t51v(Hp) +return oUA({_value=Hp,_wrapped=true},A1)end +oUA(A1,{__call=function(Tee9V,znHly)return t51v(znHly)end,__index=function(cD,I,...)return +gOp2cWZ[I]end})function A1.chain(AN9)return t51v(AN9)end +function A1:value()return self._value end;gOp2cWZ.chain,gOp2cWZ.value=A1.chain,A1.value +for CCI,Ax_b in l(S1wg_DG)do if -qv~='operator'then -MkxwoCeK[qv]=function(MBdHQ,...)local STXAhhM= -v(MBdHQ)=='table'and PizLA9mj(MBdHQ,'_wrapped')or false;if STXAhhM then -local assFn=MBdHQ._value;local EXpWzv=pbEt6T(assFn,...)return _8KO(EXpWzv)else -return pbEt6T(MBdHQ,...)end end end end;MkxwoCeK.operator=S1wg_DG.operator -MkxwoCeK.op=S1wg_DG.operator -MkxwoCeK.import=function(kq,up)kq=kq or _ENV or _G -local wlI_l=S1wg_DG.functions()for nK7J,xv in kyWtqIf0(wlI_l)do -if PizLA9mj(kq,xv)~=nil then if not up then -rawset(kq,xv,S1wg_DG[xv])end else rawset(kq,xv,S1wg_DG[xv])end end -return kq end;AT._VERSION='Moses v'..SWFtRywD -AT._URL='http://github.com/Yonaba/Moses' -AT._LICENSE='MIT <http://raw.githubusercontent.com/Yonaba/Moses/master/LICENSE>'AT._DESCRIPTION='utility-belt library for functional programming in Lua' -return AT end
\ No newline at end of file +CCI~='operator'then +gOp2cWZ[CCI]=function(Hgc1S,...)local gszf= +v(Hgc1S)=='table'and PizLA9mj(Hgc1S,'_wrapped')or false +if gszf then +local GnYt=Hgc1S._value;local L7g=Ax_b(GnYt,...)return t51v(L7g)else return Ax_b(Hgc1S,...)end end end end;gOp2cWZ.operator=S1wg_DG.operator;gOp2cWZ.op=S1wg_DG.operator +gOp2cWZ.import=function(_IO9,zcnTZ6pI)_IO9= +_IO9 or _ENV or _G;local sIPPW=S1wg_DG.functions() +for jrXq,T5V8Jm3h in +kyWtqIf0(sIPPW)do if PizLA9mj(_IO9,T5V8Jm3h)~=nil then if not zcnTZ6pI then +rawset(_IO9,T5V8Jm3h,S1wg_DG[T5V8Jm3h])end else +rawset(_IO9,T5V8Jm3h,S1wg_DG[T5V8Jm3h])end end;return _IO9 end;A1._VERSION='Moses v'..SWFtRywD +A1._URL='http://github.com/Yonaba/Moses' +A1._LICENSE='MIT <http://raw.githubusercontent.com/Yonaba/Moses/master/LICENSE>'A1._DESCRIPTION='utility-belt library for functional programming in Lua' +return A1 end
\ No newline at end of file diff --git a/spec/array_spec.lua b/spec/array_spec.lua index 953cdb7..6e618ad 100644 --- a/spec/array_spec.lua +++ b/spec/array_spec.lua @@ -45,6 +45,18 @@ describe('Array functions specs', function() end) end) + + describe('nsorted', function() + + it('returns the top n-values from an array', function() + local array = M.range(1,20) + assert.is_true(M.isEqual(M.nsorted(array,5),{1,2,3,4,5})) + + local function comp(a,b) return a > b end + assert.is_true(M.isEqual(M.nsorted(array,3,comp),{20,19,18})) + end) + + end) describe('shuffle', function() @@ -67,15 +79,15 @@ describe('Array functions specs', function() end) - describe('toArray', function() + describe('pack', function() it('converts a vararg list to an array', function() - assert.is_true(M.isArray(M.toArray(1,2,3,4))) - assert.is_true(M.isEqual(M.toArray(1,2,8,'d','a',0),{1,2,8,'d','a',0})) + assert.is_true(M.isArray(M.pack(1,2,3,4))) + assert.is_true(M.isEqual(M.pack(1,2,8,'d','a',0),{1,2,8,'d','a',0})) end) it('preserves input order', function() - local args = M.toArray(1,2,3,4,5) + local args = M.pack(1,2,3,4,5) for i = 1, 5 do assert.equal(args[i], i) end end) @@ -533,6 +545,20 @@ describe('Array functions specs', function() end) + describe('disjoint',function() + + it('checks if all passed-in arrays are disjoint', function() + local A = {'a'} + local B = {'a',1,3} + local C = {3,10,2} + + assert.is_false(M.disjoint(A,B)) + assert.is_true(M.disjoint(A,C)) + assert.is_false(M.disjoint(B,C)) + end) + + end) + describe('symmetricDifference',function() it('returns the symmetric difference from two arrays', function() @@ -561,6 +587,13 @@ describe('Array functions specs', function() end) + describe('duplicates',function() + it('returns a list of all duplicates in array', function() + assert.is_true(M.isEqual(M.duplicates({1,2,3,3,8,8,3,2,4}),{2,3,8})) + assert.is_true(M.isEqual(M.duplicates({true, false, true, 1, '5', '1', '5'}),{true, '5'})) + end) + end) + describe('zip',function() it('zips together values from different arrays sharing the same index', function() local names = {'Bob','Alice','James'}; local ages = {22, 23} @@ -786,16 +819,7 @@ describe('Array functions specs', function() assert.is_true(#perm == 0) end) - end) - - describe('invert',function() - - it('switches key-values pairs', function() - assert.is_true(M.isEqual(M.invert({1,2,3}),{1,2,3})) - assert.is_true(M.isEqual(M.invert({'a','b','c'}),{a = 1,b = 2,c = 3})) - end) - - end) + end) describe('concat',function() @@ -835,6 +859,28 @@ describe('Array functions specs', function() end) + describe('xpairs',function() + + it('create pairs by prepending value to array values', function() + local r = M.xpairs(1,{1,2,3}) + assert.is_true(M.isEqual(r[1],{1,1})) + assert.is_true(M.isEqual(r[2],{1,2})) + assert.is_true(M.isEqual(r[3],{1,3})) + end) + + end) + + describe('xpairsRight',function() + + it('create pairs by appending value to array values', function() + local r = M.xpairsRight(1,{1,2,3}) + assert.is_true(M.isEqual(r[1],{1,1})) + assert.is_true(M.isEqual(r[2],{2,1})) + assert.is_true(M.isEqual(r[3],{3,1})) + end) + + end) + describe('sum',function() it('returns the sum of array values', function() diff --git a/spec/func_spec.lua b/spec/func_spec.lua index be4cf2f..627f519 100644 --- a/spec/func_spec.lua +++ b/spec/func_spec.lua @@ -27,13 +27,12 @@ describe('Utility functions specs', function() end) - describe('constant', function() + describe('call', function() - it('creates a constant function',function() - local gravity = M.constant(9.81) - assert.equal(gravity(),9.81) - assert.equal(gravity(10), 9.81) - assert.equal(gravity(nil), 9.81) + it('calls f(...) and returns the results',function() + assert.equal(M.call(math.pow, 2, 3), 8) + assert.equal(M.call(string.len, 'hello' ), 5) + assert.equal(M.call(table.concat, {1,2,3,4,5}, ',', 2, 4),"2,3,4") end) end) @@ -59,6 +58,64 @@ describe('Utility functions specs', function() end) + describe('thread', function() + + it('threads a value through functions',function() + local function inc(x) return x + 1 end + local function double(x) return 2 * x end + local function square(x) return x * x end + assert.equal(M.thread(2, inc, double, square), 36) + assert.equal(M.thread(3, double, inc, square), 49) + assert.equal(M.thread(4, square, double, inc), 33) + assert.equal(M.thread(5, square, inc, double), 52) + end) + + it('accepts funcs taking more than one arg',function() + local function inc(x) return x + 1 end + local function add(x, y) return x + y end + local function pow(x, y) return x ^ y end + assert.equal(M.thread(2, inc, {add, 3}, {pow, 2}), 36) + assert.equal(M.thread(2, {add, 4}, inc, {pow, 2}), 49) + end) + + end) + + describe('threadRight', function() + + it('threads a value through functions',function() + local function inc(x) return x + 1 end + local function double(x) return 2 * x end + local function square(x) return x * x end + assert.equal(M.threadRight(2, inc, double, square), 36) + assert.equal(M.threadRight(3, double, inc, square), 49) + assert.equal(M.threadRight(4, square, double, inc), 33) + assert.equal(M.threadRight(5, square, inc, double), 52) + end) + + it('accepts funcs taking more than one arg',function() + local function inc(x) return x + 1 end + local function add(x, y) return x + y end + local function pow(x, y) return x ^ y end + assert.equal(M.threadRight(2, inc, {add, 3}, {pow, 2}), 64) + assert.equal(M.threadRight(2, {add, 4}, inc, {pow, 2}), 128) + end) + + end) + + describe('dispatch', function() + + it('produces a dispatch function',function() + local f = M.dispatch( + function() return nil end, + function (v) return v+1 end, + function (v) return 2*v end + ) + assert.equal(f(5),6) + assert.equal(f(7),8) + end) + + end) + describe('memoize', function() local fib_time, fib_value, mfib_time, mfib_value @@ -301,6 +358,48 @@ describe('Utility functions specs', function() end) + describe('both', function() + + it('returns a truthy func when all funcs returns true',function() + local f = M.both( + function(x) return x > 0 end, + function(x) return x < 10 end, + function(x) return x % 2 == 0 end + ) + assert.is_true(f(2)) + assert.is_true(f(8)) + assert.is_false(f(9)) + end) + + end) + + describe('either', function() + + it('returns a truthy func when at least one of its funcs returns true',function() + local f = M.either( + function(x) return x > 0 end, + function(x) return x % 2 == 0 end + ) + assert.is_true(f(0)) + assert.is_false(f(-3)) + end) + + end) + + describe('neither', function() + + it('returns a truthy func when neither of its funcs returns true',function() + local f = M.neither( + function(x) return x > 10 end, + function(x) return x % 2 == 0 end + ) + assert.is_false(f(12)) + assert.is_false(f(8)) + assert.is_true(f(7)) + end) + + end) + describe('uniqueId', function() it('returns an unique (for the current session) integer Id',function() @@ -355,19 +454,56 @@ describe('Utility functions specs', function() end) end) + + describe('skip', function() + + it('consumes the first n values of an iterator',function() + local w = "hello" + local char = string.gmatch(w,'.') + local iter = M.skip(char, 3) + assert.equal(iter(), 'l') + assert.equal(iter(), 'o') + end) + + it('consumes the first n values of an iterator',function() + local w = "lua" + local char = string.gmatch(w,'.') + local iter = M.skip(char) + assert.equal(iter(), 'u') + assert.equal(iter(), 'a') + end) + + end) - describe('array', function() + describe('tabulate', function() it('iterates a given iterator and returns its values in an array',function() - local letters = M.array(('Lua'):gmatch('.')) + local letters = M.tabulate(('Lua'):gmatch('.')) assert.is_true(M.isEqual(letters,{'L','u','a'})) - local numbers = M.array(pairs(M.range(1,10))) + local numbers = M.tabulate(pairs(M.range(1,10))) assert.is_true(M.isEqual(numbers,M.range(1,10))) end) end) + describe('iterlen', function() + + it('returns the iterator length',function() + local text = 'letters' + local chars = string.gmatch(text, '.') + assert.equal(M.iterlen(chars),7) + end) + + it('it consumes the iterator',function() + local text = 'lua' + local chars = string.gmatch(text, '.') + assert.equal(M.iterlen(chars),3) + assert.is_nil(chars()) + end) + + end) + describe('castArray', function() it('converts value to an array',function() @@ -439,7 +575,18 @@ describe('Utility functions specs', function() end) - describe('rearg', function() + describe('noarg', function() + + it('returns a function with an arity of 0',function() + local f = M.noarg(function (x) return x or 'default' end) + assert.equal(f(1), 'default') + assert.equal(f(function() end, 3), 'default') + assert.equal(f(nil), 'default') + end) + + end) + + describe('rearg', function() it('creates a function with args reordered',function() local f = M.rearg(function(...) return ... end, {3,2,1}) diff --git a/spec/object_spec.lua b/spec/object_spec.lua index 5327ea5..2e8dc49 100644 --- a/spec/object_spec.lua +++ b/spec/object_spec.lua @@ -43,6 +43,41 @@ describe('Object functions specs', function() end) + describe('spreadPath', function() + + it('spreads objects under property path',function() + local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} + M.spreadPath(obj, 'c', 'f') + assert.equal(obj.a, 1) + assert.equal(obj.b, 2) + assert.equal(obj.d, 3) + assert.equal(obj.e, 4) + assert.equal(obj.g, 5) + assert.is_true(M.isEmpty(obj.c)) + assert.is_true(M.isEmpty(obj.c.f)) + end) + + end) + + describe('flattenPath', function() + + it('flattens objects under property path',function() + local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} + M.flattenPath(obj, 'c', 'f') -- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {d = 3, e = 4, f = {g = 5}}} + assert.equal(obj.a, 1) + assert.equal(obj.b, 2) + assert.equal(obj.d, 3) + assert.equal(obj.e, 4) + assert.equal(obj.g, 5) + assert.equal(M.size(obj.c), 3) + assert.equal(obj.c.d, 3) + assert.equal(obj.c.e, 4) + assert.equal(M.size(obj.c.f), 1) + assert.equal(obj.c.f.g, 5) + end) + + end) + describe('kvpairs', function() it('converts key-values pairs in object to array-list of k,v pairs',function() @@ -66,6 +101,16 @@ describe('Object functions specs', function() end) + describe('invert',function() + + it('switches key-values pairs', function() + assert.is_true(M.isEqual(M.invert({1,2,3}),{1,2,3})) + assert.is_true(M.isEqual(M.invert({'a','b','c'}),{a = 1,b = 2,c = 3})) + assert.is_true(M.isEqual(M.invert({x = 4, y = 2}),{[2]='y',[4]='x'})) + end) + + end) + describe('property', function() it('Returns a function that will return the key property of any passed-in object.',function() @@ -446,6 +491,17 @@ describe('Object functions specs', function() end) + describe('type', function() + + it('returns the type of the passed-in object',function() + assert.equal(M.type('string'),'string') + assert.equal(M.type(table),'table') + assert.equal(M.type(1), 'number') + assert.equal(M.type(io.open('f','w')),'file') + end) + + end) + describe('isEmpty', function() it('returns "true" if arg is an empty array',function() diff --git a/spec/table_spec.lua b/spec/table_spec.lua index 6ccf2bf..5a86aa9 100644 --- a/spec/table_spec.lua +++ b/spec/table_spec.lua @@ -27,9 +27,10 @@ describe('Table functions specs', function() it('can reference the given table', function() local t = {1,2,3} - M.each(t,function(v,i,mul) + local mul = 5 + M.each(t,function(v,i) t[i] = v*mul - end,5) + end) assert.is_true(M.isEqual(t,{5,10,15})) end) @@ -133,6 +134,35 @@ describe('Table functions specs', function() end) end) + describe('allEq', function() + + it('checks if all values are equal', function() + assert.is_true(M.allEqual({1,1,1,1,1}, comp)) + assert.is_false(M.allEqual({1,1,2,1,1}, comp)) + + local t1 = {1, 2, {3}} + local t2 = {1, 2, {3}} + assert.is_true(M.allEqual({t1, t2})) + end) + + it('can use a custom comp function to compare values', function() + local t1 = {x = 1, y = 0} + local t2 = {x = 1, y = 0} + local t3 = {x = 1, y = 2} + local t4 = {x = 1, y = 2} + local function compx(a, b) return a.x == b.x end + local function compy(a, b) return a.y == b.y end + + assert.is_true(M.allEqual({t1, t2}, compx)) + assert.is_true(M.allEqual({t1, t2}, compy)) + assert.is_true(M.allEqual({t3, t4}, compx)) + assert.is_true(M.allEqual({t3, t4}, compy)) + assert.is_true(M.allEqual({t1, t2, t3, t4}, compx)) + assert.is_false(M.allEqual({t1, t2, t3, t4}, compy)) + end) + + end) + describe('cycle', function() it('loops n times on a list', function() @@ -230,14 +260,24 @@ describe('Table functions specs', function() end) end) + + describe('best', function() + + it('select the best candidate in a table', function() + local words = {'Lua', 'Programming', 'Language'} + assert.equal(M.best(words, function(a,b) return #a > #b end), 'Programming') + assert.equal(M.best(words, function(a,b) return #a < #b end), 'Lua') + end) + + end) - describe('reduceby', function() + describe('reduceBy', function() it('folds a collection (left to right) for specific values', function() local function even(v) return v%2==0 end local function odd(v) return v%2~=0 end - assert.equal(M.reduceby({1,2,3,4},function(memo,v) return memo+v end,even,0), 6) - assert.equal(M.reduceby({1,2,3,4},function(memo,v) return memo+v end,odd,0), 4) + assert.equal(M.reduceBy({1,2,3,4},function(memo,v) return memo+v end,even,0), 6) + assert.equal(M.reduceBy({1,2,3,4},function(memo,v) return memo+v end,odd,0), 4) end) end) @@ -421,7 +461,7 @@ describe('Table functions specs', function() assert.is_true(M.isEqual(M.invoke({'a','bea','cdhza'},string.len), {1,3,5})) - assert.is_true(M.isEqual(M.invoke({{2,3,2},{13,8,10},{0,-5}},M.sort), + assert.is_true(M.isEqual(M.invoke({{2,3,2},{13,8,10},{0,-5}},M.ary(M.sort,1)), {{2,2,3},{8,10,13},{-5,0}})) assert.is_true(M.isEqual(M.invoke({{x = 1, y = 2},{x = 3, y=4}},'x'), {1,3})) @@ -511,6 +551,58 @@ describe('Table functions specs', function() end) end) + + describe('sortedk', function() + + it('iterates on sorted keys', function() + local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 + local ok_tbl = {12, 6, 5, 10, 8} + local sorted = {} + for k, v in M.sortedk(tbl) do sorted[k] = v end + for k in ipairs(sorted) do + assert.equal(sorted[k], ok_tbl[k]) + end + end) + + it('can take a comparison function', function() + local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 + local ok_tbl = {8, 10, 5, 6, 12} + local sorted = {} + for k, v in M.sortedk(tbl, function(a, b) return a > b end) do + sorted[#sorted +1] = {k, v} + end + for k, pr in ipairs(sorted) do + assert.equal(pr[2], ok_tbl[k]) + end + end) + + end) + + describe('sortedv', function() + + it('iterates on sorted values', function() + local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 + local ok_tbl = {5, 6, 8, 10, 12} + local sorted = {} + for k, v in M.sortedv(tbl) do sorted[#sorted + 1] = {k, v} end + for k, pr in ipairs(sorted) do + assert.equal(pr[2], ok_tbl[k]) + end + end) + + it('can take a comparison function', function() + local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 + local ok_tbl = {12, 10, 8, 6, 5} + local sorted = {} + for k, v in M.sortedv(tbl, function(a, b) return a > b end) do + sorted[#sorted +1] = {k, v} + end + for k, pr in ipairs(sorted) do + assert.equal(pr[2], ok_tbl[k]) + end + end) + + end) describe('sortBy', function() @@ -544,19 +636,10 @@ describe('Table functions specs', function() assert.is_true(M.isEqual(M.groupBy({0,1,2,3,4,5,6},function(value) return value%2==0 and 'even' or 'odd' end),{even = {0,2,4,6},odd = {1,3,5}})) - assert.is_true(M.isEqual(M.groupBy({0,'a',true, false,nil,b,0.5},type),{number = {0,0.5},string = {'a'},boolean = {true,false}})) - assert.is_true(M.isEqual(M.groupBy({'one','two','three','four','five'},string.len),{[3] = {'one','two'},[4] = {'four','five'},[5] = {'three'}})) end) - - it('can takes extra-args', function() - - assert.is_true(M.isEqual(M.groupBy({3,9,10,12,15}, function(v,k,x) return v%x == 0 end,2), {[false] = {3,9,15}, [true] = {10,12}})) - assert.is_true(M.isEqual(M.groupBy({3,9,10,12,15}, function(v,k,x) return v%x == 0 end,3), {[false] = {10}, [true] = {3,9,12,15}})) - - end) end) |