Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Yonaba/Moses.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonaba <roland.yonaba@gmail.com>2018-09-12 14:59:02 +0300
committerYonaba <roland.yonaba@gmail.com>2018-09-12 14:59:02 +0300
commit1f0f01b8ae5297671ff7767b3ca7952293b67137 (patch)
tree476b1bd6a3f58fe416dcf59f0f11c9164f13b873
parentab8827720f20482f9af6b794e5efca5ad6b8a209 (diff)
Bump to 2.1.0 (see CHANGELOG)
-rw-r--r--CHANGELOG.md65
-rw-r--r--README.md5
-rw-r--r--doc/index.html1240
-rw-r--r--doc/manual/tutorial.md.html489
-rw-r--r--doc/tutorial.md429
-rw-r--r--moses.lua607
-rw-r--r--moses_min.lua878
-rw-r--r--spec/array_spec.lua74
-rw-r--r--spec/func_spec.lua167
-rw-r--r--spec/object_spec.lua56
-rw-r--r--spec/table_spec.lua113
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, ...)`.
diff --git a/README.md b/README.md
index 9c4d1ef..f2b8544 100644
--- a/README.md
+++ b/README.md
@@ -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>&lt;</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>&lt;</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>&lt;</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">-- =&gt; 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">-- =&gt; 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">-- =&gt; 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">-- =&gt; true
+</span>M.allEqual({t1, t2}, compy) <span class="comment">-- =&gt; true
+</span>M.allEqual({t3, t4}, compx) <span class="comment">-- =&gt; true
+</span>M.allEqual({t3, t4}, compy) <span class="comment">-- =&gt; true
+</span>M.allEqual({t1, t2, t3, t4}, compx) <span class="comment">-- =&gt; true
+</span>M.allEqual({t1, t2, t3, t4}, compy) <span class="comment">-- =&gt; 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 &gt; #b <span class="keyword">end</span>) <span class="comment">-- =&gt; 'Programming'
+</span>M.best(words, <span class="keyword">function</span>(a,b) <span class="keyword">return</span> #a &lt; #b <span class="keyword">end</span>) <span class="comment">-- =&gt; '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">-- =&gt; -17
-</span>M.reduceby(val, add, pos) <span class="comment">-- =&gt; 19</span>
+M.reduceBy(val, add, neg) <span class="comment">-- =&gt; -17
+</span>M.reduceBy(val, add, pos) <span class="comment">-- =&gt; 19</span>
</pre>
@@ -378,8 +429,8 @@ M.reduceby(val, add, neg) <span class="comment">-- =&gt; -17
<pre>
-M.reduceby(val, add, neg, <span class="number">17</span>) <span class="comment">-- =&gt; 0
-</span>M.reduceby(val, add, pos, -<span class="number">19</span>) <span class="comment">-- =&gt; 0</span>
+M.reduceBy(val, add, neg, <span class="number">17</span>) <span class="comment">-- =&gt; 0
+</span>M.reduceBy(val, add, pos, -<span class="number">19</span>) <span class="comment">-- =&gt; 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">-- =&gt
</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">-- =&gt; 1 12
+</span><span class="comment">-- =&gt; 2 6
+</span><span class="comment">-- =&gt; 3 5
+</span><span class="comment">-- =&gt; 4 10
+</span><span class="comment">-- =&gt; 5 8
+</span>
+<span class="keyword">local</span> <span class="keyword">function</span> comp(a,b) <span class="keyword">return</span> a &gt; 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">-- =&gt; 5 8
+</span><span class="comment">-- =&gt; 4 10
+</span><span class="comment">-- =&gt; 3 5
+</span><span class="comment">-- =&gt; 2 6
+</span><span class="comment">-- =&gt; 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">-- =&gt; 3 5
+</span><span class="comment">-- =&gt; 2 6
+</span><span class="comment">-- =&gt; 5 8
+</span><span class="comment">-- =&gt; 4 10
+</span><span class="comment">-- =&gt; 1 12
+</span>
+<span class="keyword">local</span> <span class="keyword">function</span> comp(a,b) <span class="keyword">return</span> a &gt; 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">-- =&gt; 1 12
+</span><span class="comment">-- =&gt; 4 10
+</span><span class="comment">-- =&gt; 5 8
+</span><span class="comment">-- =&gt; 2 6
+</span><span class="comment">-- =&gt; 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 &gt; b <span class="keyword">end</span>
+M.nsorted(array,<span class="number">5</span>, comp) <span class="comment">-- =&gt; {5,4,3,2,1}</span>
+</pre>
+
+
+<p><code>n</code> defaults to 1 and <code>comp</code> defaults to the <code>&lt;</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">-- =&gt; {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">-- =&gt; "{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">-- =&gt; "{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">-- =&gt; 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">-- =&gt; "{
<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">-- =&gt; "{'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">-- =&gt; "{'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">-- =&gt; "{'a',2,1}"</span>
+M.intersection(A,B,C) <span class="comment">-- =&gt; "{'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">-- =&gt; false
+</span>M.disjoint(A,C) <span class="comment">-- =&gt; true
+</span>M.disjoint(B,C) <span class="comment">-- =&gt; 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">-- =&gt; {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">-- =&gt; "{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">-- =&gt; {{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">-- =&gt; {{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">-- =&gt; 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">-- =&gt; 8
+</span>M.call(<span class="global">string</span>.len, <span class="string">'hello'</span> ) <span class="comment">-- =&gt; 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">-- =&gt; {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">-- =&gt; 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">-- =&gt; 36
+</span>M.thread(<span class="number">3</span>, double, inc, square) <span class="comment">-- =&gt; 49
+</span>M.thread(<span class="number">4</span>, square, double, inc) <span class="comment">-- =&gt; 33
+</span>M.thread(<span class="number">5</span>, square, inc, double) <span class="comment">-- =&gt; 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">-- =&gt; 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">-- =&gt; 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">-- =&gt; 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">-- =&gt; 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">-- =&gt; 6
+</span>f(<span class="number">7</span>) <span class="comment">-- =&gt; 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 &gt; <span class="number">0</span> <span class="keyword">end</span>,
+ <span class="keyword">function</span>(x) <span class="keyword">return</span> x &lt; <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">-- =&gt; true
+</span>f(<span class="number">8</span>) <span class="comment">-- =&gt; true
+</span>f(<span class="number">9</span>) <span class="comment">-- =&gt; 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 &gt; <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">-- =&gt; true
+</span>f(-<span class="number">3</span>) <span class="comment">-- =&gt; 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 &gt; <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">-- =&gt; false
+</span>f(<span class="number">8</span>) <span class="comment">-- =&gt; false
+</span>f(<span class="number">7</span>) <span class="comment">-- =&gt; 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">-- =&gt; 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">-- =&gt; '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">-- =&gt; '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">-- =&gt; 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">-- =&gt; {'l','e','t','t','e','r','s'}</span>
+M.tabulate(chars) <span class="comment">-- =&gt; {'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">-- =&gt; 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">-- =&gt; 3
+</span>chars() <span class="comment">-- =&gt; 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">-- =&gt; 'default'
+</span>f(<span class="keyword">function</span>() <span class="keyword">end</span>, <span class="number">3</span>) <span class="comment">-- =&gt; '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">-- =&gt; {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">-- =&gt; {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">-- =&gt; "{a=1, b=2, c=3}"
+</span>M.invert {x = <span class="number">1</span>, y = <span class="number">2</span>} <span class="comment">-- =&gt; "{'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">-- =&gt;
</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">-- =&gt; 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">-- =&gt; 'string'
+</span>M.<span class="global">type</span>(<span class="global">table</span>) <span class="comment">-- =&gt; 'table'
+</span>M.<span class="global">type</span>(<span class="keyword">function</span>() <span class="keyword">end</span>) <span class="comment">-- =&gt; '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">-- =&gt; '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 ?
diff --git a/moses.lua b/moses.lua
index 924bbea..ffdaeb0 100644
--- a/moses.lua
+++ b/moses.lua
@@ -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)