1---
2-- lodash for lua
3-- @module lodash
4-- @author Ted Moghimi
5-- @license MIT
6
7-- 20200120; added _.isEqual ( http://lua-users.org/lists/lua-l/2014-09/msg00463.html )
8
9local _ = {
10    _VERSION = '0.03'
11}
12
13--- Array
14-- @section Array
15
16---
17-- Creates an array of elements split into groups the length of size.
18-- If collection can’t be split evenly, the final chunk will be the
19-- remaining elements.
20-- @usage local t = _.chunk({'x', 'y', 'z', 1, 2, 3, 4, true , false}, 4)
21-- _.print(t)
22-- --> {{"x", "y", "z", 1}, {2, 3, 4, true}, {false}}
23--
24-- @param array The array to process.
25-- @param[opt=1] size The length of each chunk.
26-- @return the new array containing chunks.
27_.chunk = function (array, size)
28    local t = {}
29    local size = size == 0 and 1 or size or 1
30    local c, i = 1, 1
31    while true do
32        t[i] = {}
33        for j = 1, size do
34            _.push(t[i], array[c])
35            c = c + 1
36        end
37        if _.gt(c, #array) then
38            break
39        end
40        i = i + 1
41    end
42    return t
43end
44
45---
46-- Creates an array with all falsey values removed. The values false,
47-- nil are falsey.
48-- @usage local t = _.compact({'x', 'y', nil, 1, 2, 3, false, true , false})
49-- _.print(t)
50-- --> {"x", "y", 1, 2, 3, true}
51--
52-- @param array The array to compact
53-- @return Returns the new array of filtered values
54_.compact = function (array)
55    local t = {}
56    for k, v in pairs(array) do
57        if v then
58            _.push(t, v)
59        end
60    end
61    return t
62end
63
64
65---
66-- Creates an array of unique array values not included in the other
67-- provided arrays.
68-- @usage _.print(_.difference({3, 1, 2, 9, 5, 9}, {4, 5}, {9, 1}))
69-- --> {3, 2}
70--
71-- @param array The array to inspect.
72-- @param ... The arrays of values to exclude.
73-- @return Returns the new array of filtered values.
74_.difference = function (array, ...)
75    local t = {}
76    local c = 1
77    local tmp = _.table(...)
78    for k, v in ipairs(array) do
79        while not _.isNil(tmp[c]) do
80            for j, v2 in ipairs(tmp[c]) do
81                if v == v2 then goto doubleBreak end
82            end
83            c = c + 1
84        end
85        _.push(t, v)
86        ::doubleBreak::
87        c = 1
88    end
89    return t
90end
91
92---
93-- Creates a slice of array with n elements dropped from the beginning.
94-- @usage _.print(_.drop({1, 2, 3, 4, 5, 6}, 2))
95-- --> {3, 4, 5, 6}
96--
97-- @param array The array to query.
98-- @param[opt=1] n The number of elements to drop.
99-- @return Returns the slice of array.
100_.drop = function (array, n)
101    local n = n or 1
102    return _.slice(array, n + 1)
103end
104
105
106local callIteratee = function (predicate, selfArg, ...)
107    local result
108    local predicate = predicate or _.identity
109    if selfArg then
110        result = predicate(selfArg, ...)
111    else
112        result = predicate(...)
113    end
114    return result
115end
116
117---
118-- Creates a slice of array with n elements dropped from the end.
119-- @usage _.print(_.dropRight({1, 2, 3, 4, 5, 6}, 2))
120-- --> {1, 2, 3, 4}
121--
122-- @param array The array to query.
123-- @param[opt=1] n The number of elements to drop.
124-- @return Returns the slice of array.
125_.dropRight = function (array, n)
126    local n = n or 1
127    return _.slice(array, nil, #array - n)
128end
129
130
131local dropWhile = function(array, predicate, selfArg, start, step, right)
132    local t = {}
133    local c = start
134    while not _.isNil(array[c]) do
135        ::cont::
136        if #t == 0 and
137            callIteratee(predicate, selfArg, array[c], c, array) then
138            c = c + step
139            goto cont
140        end
141        if right then
142            _.enqueue(t, array[c])
143        else
144            _.push(t, array[c])
145        end
146        c = c + step
147    end
148    return t
149end
150
151---
152-- Creates a slice of array excluding elements dropped from the end.
153-- Elements are dropped until predicate returns falsey.
154-- @usage _.print(_.dropRightWhile({1, 5, 2, 3, 4, 5, 4, 4}, function(n)
155--    return n > 3
156-- end))
157-- --> {1, 5, 2, 3}
158--
159-- @param array The array to query.
160-- @param[opt=_.identity] predicate The function to invoked per iteratin.
161-- @param[opt] selfArg The self binding of predicate.
162-- @return Return the slice of array.
163_.dropRightWhile = function(array, predicate, selfArg)
164    return dropWhile(array, predicate, selfArg, #array, -1, true)
165end
166
167---
168-- Creates a slice of array excluding elements dropped from the beginning.
169-- Elements are dropped until predicate returns falsey.
170-- @usage _.print(_.dropWhile({1, 2, 2, 3, 4, 5, 4, 4, 2}, function(n)
171--    return n < 3
172-- end))
173-- --> {3, 4, 5, 4, 4, 2}
174--
175-- @param array The array to query.
176-- @param[opt=_.idenitity] predicate The function invoked per iteration.
177-- @param[opt] selfArg The self binding of predicate.
178-- @return Return the slice of array.
179_.dropWhile = function(array, predicate, selfArg)
180    return dropWhile(array, predicate, selfArg, 1, 1)
181end
182
183
184---
185-- Push value to first element of array
186---
187--@Usage local array = {1, 2, 3, 4}
188-- _.enqueue(array, 5)
189-- _print(array)
190-- --> {5, 1, 2, 3, 4}
191--
192-- @param array; Array to modify
193-- @param: value; Value to fill first element of Array with
194-- @return array
195_.enqueue = function (array, value)
196    return table.insert(array, 1, value)
197end
198
199---
200-- Fills elements of array with value from start up to, including, end.
201-- @usage local array = {1, 2, 3, 4}
202-- _.fill(array, 'x', 2, 3)
203-- _.print(array)
204-- --> {1, "x", "x", 4}
205--
206-- @param array The array to fill.
207-- @param value The value to fill array with.
208-- @param[opt=1] start The start position.
209-- @param[opt=#array] stop The end position.
210-- @return Returns array.
211_.fill = function (array, value, start, stop)
212    local start = start or 1
213    local stop = stop or #array
214    for i=start, stop, start > stop and -1 or 1 do
215        array[i] = value
216    end
217    return  array
218end
219
220
221local findIndex = function(array, predicate, selfArg, start, step)
222    local c = start
223    while not _.isNil(array[c]) do
224        if callIteratee(predicate, selfArg, array[c], c, array) then
225            return c
226        end
227        c = c + step
228    end
229    return -1
230end
231
232---
233-- This method is like [_.find](#_.find) except that it returns the index of the
234-- first element predicate returns truthy for instead of the element itself.
235-- @usage _.print(_.findIndex({{a = 1}, {a = 2}, {a = 3}, {a = 2}, {a = 3}}, function(v)
236--     return v.a == 3
237-- end))
238-- --> 3
239--
240-- @param array The array to search.
241-- @param[opt=_.idenitity] predicate The function invoked per iteration.
242-- @param[opt] selfArg The self binding of predicate.
243-- @return Returns the index of the found element, else -1.
244_.findIndex = function (array, predicate, selfArg)
245    return findIndex(array, predicate, selfArg, 1, 1)
246end
247
248---
249-- This method is like [_.findIndex](#_.findIndex) except that it iterates over
250-- elements of collection from right to left.
251-- @usage _.print(_.findLastIndex({{a = 1}, {a = 2}, {a = 3}, {a = 2}, {a = 3}}, function(v)
252--     return v.a == 3
253-- end))
254-- --> 5
255--
256-- @param array The array to search.
257-- @param[opt=_.idenitity] predicate The function invoked per iteration.
258-- @param[opt] selfArg The self binding of predicate.
259-- @return Returns the index of the found element, else -1.
260_.findLastIndex = function (array, predicate, selfArg)
261    return findIndex(array, predicate, selfArg, #array, -1)
262end
263
264
265---
266-- Gets the first element of array.
267-- @usage _.print(_.first({'w', 'x', 'y', 'z'}))
268-- --> w
269--
270-- @param array The array to query.
271-- @return Returns the first element of array.
272_.first = function (array)
273    return array[1]
274end
275
276---
277-- Flattens a nested array.
278-- If isDeep is true the array is recursively flattened, otherwise
279-- it’s only flattened a single level.
280-- @usage _.print(_.flatten({1, 2, {3, 4, {5, 6}}}))
281-- --> {1, 2, 3, 4, {5, 6}}
282-- _.print(_.flatten({1, 2, {3, 4, {5, 6}}}, true))
283-- --> {1, 2, 3, 4, 5, 6}
284--
285-- @param array The array to flatten.
286-- @param isDeep Specify a deep flatten
287-- @return Returns the new flattened array.
288_.flatten = function(array, isDeep)
289    local t = {}
290    for k, v in ipairs(array) do
291        if _.isTable(v) then
292            local childeren
293            if isDeep then
294                childeren = _.flatten(v)
295            else
296                childeren = v
297            end
298            for k2, v2 in ipairs(childeren) do
299                _.push(t, v2)
300            end
301        else
302            _.push(t, v)
303        end
304    end
305    return t
306end
307
308---
309-- Recursively flattens a nested array.
310-- @usage _.print(_.flattenDeep({1, 2, {3, 4, {5, 6}}}))
311-- --> {1, 2, 3, 4, 5, 6}
312--
313-- @param array The array to flatten.
314-- @return Returns the new flattened array.
315_.flattenDeep = function (array)
316    return _.flatten(array, true)
317end
318
319---
320-- Gets the index at which the first occurrence of value is found in array.
321-- @usage _.print(_.indexOf({2, 3, 'x', 4}, 'x'))
322-- --> 3
323--
324-- @param array The array to search.
325-- @param value The value to search for.
326-- @param[opt=1] fromIndex The index to search from.
327-- @return  Returns the index of the matched value, else -1.
328_.indexOf = function (array, value, fromIndex)
329    return _.findIndex(array, function(n)
330        return n == value
331    end)
332end
333--
334
335---
336-- Gets all but the last element of array.
337-- @usage _.print(_.initial({1, 2, 3, 'a'}))
338-- --> {1, 2, 3}
339--
340-- @param array The array to query.
341-- @return Returns the slice of array.
342_.initial = function (array)
343    return _.slice(array, nil, #array - 1)
344end
345--
346
347---
348-- Creates an array of unique values that are included in all of the
349-- provided arrays.
350-- @usage _.print(_.intersection({1, 2}, {4, 2}, {2, 1}))
351-- --> {2}
352--
353-- @param The arrays to inspect.
354-- @return Returns the new array of shared values.
355_.intersection = function (...)
356    local tmp = _.table(...)
357    local first = table.remove(tmp, 1)
358    local t = {}
359    for i, v in ipairs(first) do
360        local notFound = false
361        for i2, v2 in ipairs(tmp) do
362            if _.indexOf(v2, v) == -1 then
363                notFound = true
364                break
365            end
366        end
367        if not notFound then
368            _.push(t, v)
369        end
370    end
371    return t
372    -- body
373end
374
375
376---
377-- Gets the last element of array.
378-- @usage _.print(_.last({'w', 'x', 'y', 'z'}))
379-- --> z
380--
381-- @param array The array to query.
382-- @return Returns the last element of array.
383_.last = function(array)
384    return array[#array]
385end
386
387---
388-- This method is like [_.indexOf](#_.indexOf) except that it iterates
389--  over elements of array from right to left.
390-- @usage _.print(_.lastIndexOf({2, 3, 'x', 4, 'x', 5}, 'x'))
391-- --> 5
392--
393-- @param array The array to search.
394-- @param value The value to search for.
395-- @param[opt=#array] fromIndex The index to search from.
396-- @return  Returns the index of the matched value, else -1.
397_.lastIndexOf = function (array, value, fromIndex)
398   return _.findLastIndex(array, function(n)
399        return n == value
400    end)
401end
402
403
404---
405-- Removes all provided values from array.
406-- @usage local array = {1, 2, 3, 4, 5, 4, 1, 2, 3}
407-- _.pull(array, 2, 3)
408-- _.print(array)
409-- --> {1, 4, 5, 4, 1}
410-- @param array The array to modify.
411-- @param ... The values to remove.
412-- @return Returns array
413_.pull = function(array, ...)
414    local i = 1
415    while not _.isNil(array[i]) do
416        for k, v in ipairs(_.table(...)) do
417            if array[i] == v then
418                table.remove(array, i)
419                goto cont
420            end
421        end
422        i = i + 1
423        ::cont::
424    end
425    return array
426end
427
428_.push = function (array, value)
429    return table.insert(array, value)
430end
431
432---
433-- Removes elements from array corresponding to the given indexes and
434-- returns an array of the removed elements. Indexes may be specified
435-- as an array of indexes or as individual arguments.
436-- @usage local array = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
437-- local t = _.pullAt(array, 4, 9, 8)
438-- _.print(array)
439-- --> {"a", "b", "c", "e", "f", "g", "j"}
440-- _.print(t)
441-- --> {"d", "h", "i"}
442--
443-- @param array The array to modify.
444-- @param ... The indexes of elements to remove
445-- @return Returns the new array of removed elements.
446_.pullAt = function (array, ...)
447    local t = {}
448    local tmp = _.table(...)
449    table.sort(tmp, function(a, b)
450        return _.gt(a, b)
451    end)
452    for i, index in ipairs(tmp) do
453        _.enqueue(t, table.remove(array, index))
454    end
455    return t
456end
457
458---
459-- Removes all elements from array that predicate returns truthy for
460-- and returns an array of the removed elements.
461-- @usage local array = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 1, 2, 3, 5, 4}
462-- local t = _.remove(array, function(value)
463--     return value > 4
464-- end)
465-- _.print(array)
466-- --> {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}
467-- _.print(t)
468-- --> {5, 6, 7, 5, 6, 5}
469--
470-- @param array The array to modify.
471-- @param predicate The function invoked per iteration.
472-- @return Returns the new array of removed elements
473_.remove = function(array, predicate)
474    local t = {}
475    local c = 1
476    local predicate = predicate or _.identity
477    while not _.isNil(array[c]) do
478        if predicate(array[c], c, array) then
479            _.push(t, table.remove(array, c))
480            goto cont
481        end
482        c = c + 1
483        ::cont::
484    end
485    return t
486end
487
488
489---
490-- Gets all but the first element of array.
491-- @usage _.print(_.rest({1, 2, 3, 'a'}))
492-- --> {2, 3, 'a'}
493-- @param array The array to query.
494-- @return Returns the slice ofa array.
495_.rest = function (array)
496    return _.slice(array, 2, #array)
497end
498
499
500---
501-- Reverses the array so the first element becomes the last, the second
502-- element becomes the second to last, and so on.
503-- @usage _.print(_.reverse({1, 2, 3, 'a', 'b'}))
504-- --> {'b', 'a', 3, 2, 1}
505--
506-- @param array The array to mutate.
507-- @return Returns the new reversed array.
508_.reverse = function (array)
509    local t = {}
510    for i, v in ipairs(array) do
511        _.enqueue(t, v)
512    end
513    return t
514end
515
516
517---
518-- Creates a slice of array from start up to, including, end.
519-- @usage _.print(_.slice({1, 2, 3, 4, 5, 6}, 2, 3))
520-- --> {2, 3}
521--
522-- @param array The array to slice.
523-- @param[opt=1] start The start position.
524-- @param[opt=#array] stop The end position
525-- @return Returns the slice of array.
526_.slice = function (array, start, stop)
527    local start = start or 1
528    local stop = stop or #array
529    local t = {}
530    for i=start, stop do
531        t[i - start + 1] = array[i]
532    end
533    return t
534end
535
536---
537-- Creates a slice of array with n elements taken from the beginning.
538-- @usage _.print(_.take({1, 2, 3, 4, 5}, 3))
539-- --> {1, 2, 3}
540--
541-- @param array The array to query.
542-- @param[opt=1] n The number of elements to take.
543-- @return Returns the slice of array.
544_.take = function(array, n)
545    local n = n or 1
546    return _.slice(array, 1, n)
547end
548
549
550---
551-- Creates a slice of array with n elements taken from the end.
552-- @usage _.print(_.takeRight({1, 2, 3, 4, 5}, 3))
553-- --> {3, 4, 5}
554--
555-- @param array The array to query.
556-- @param[opt=1] n The number of elements to take.
557-- @return Returns the slice of array.
558_.takeRight = function (array, n)
559    local n = n or 1
560    return _.slice(array, #array - n +1)
561end
562
563local takeWhile = function(array, predicate, selfArg, start, step, right)
564    local t = {}
565    local c = start
566    while not _.isNil(array[c]) do
567        if callIteratee(predicate, selfArg, array[c], c, array) then
568            if right then
569                _.enqueue(t, array[c])
570            else
571                _.push(t, array[c])
572            end
573        else
574            break
575        end
576        c = c + step
577    end
578    return t
579end
580
581---
582-- Creates a slice of array with elements taken from the end. Elements
583-- are taken until predicate returns falsey. The predicate is bound to
584-- selfArg and invoked with three arguments: (value, index, array).
585-- @usage _.print(_.takeRightWhile({1, 2, 3, 4, 5, 6, 7, 8}, function(n)
586--     return n > 4
587-- end))
588-- --> {5, 6, 7, 8}
589--
590-- @param array The array to query.
591-- @param predicate The function invoked per iteration.
592-- @param selfArg The self binding of predicate.
593_.takeRightWhile = function (array, predicate, selfArg)
594    return takeWhile(array, predicate, selfArg, #array, -1, true)
595end
596
597---
598-- Creates an array of unique values, from all of the
599-- provided arrays.
600-- @usage _.print(_.union({1, 2}, {4, 2}, {2, 1}))
601-- --> {1, 2, 4}
602--
603-- @param ... The arrays to inspect
604_.union = function (...)
605    local tmp = _.table(...)
606    local t = {}
607    for i, array in ipairs(tmp) do
608        for i2, v in ipairs(array) do
609            if _.indexOf(t, v) == -1 then
610                _.push(t, v)
611            end
612        end
613    end
614    return t
615end
616
617
618
619---
620-- Creates a slice of array with elements taken from the beginning. Elements
621-- are taken until predicate returns falsey. The predicate is bound to
622-- selfArg and invoked with three arguments: (value, index, array).
623-- @usage _.print(_.takeWhile({1, 2, 3, 4, 5, 6, 7, 8}, function(n)
624--     return n < 5
625-- end))
626-- --> {1, 2, 3, 4}
627--
628-- @param array The array to query.
629-- @param predicate The function invoked per iteration.
630-- @param selfArg The self binding of predicate.
631_.takeWhile = function (array, predicate, selfArg)
632    return takeWhile(array, predicate, selfArg, 1, 1)
633end
634
635---
636-- Creates a duplicate-free version of an array in which only the first
637-- occurence of each element is kept. If an iteratee function is provided
638-- it’s invoked for each element in the array to generate the criterion
639-- by which uniqueness is computed. The iteratee is bound to thisArg and
640-- invoked with three arguments: (value, index, array).
641-- @usage _.print(_.uniq({1, 3, 2, 2}))
642-- --> {1, 3, 2}
643--_.print(_.uniq({{x=1}, {x=2}, {x=2}, {x=3}, {x=1}}, function(n)
644--     return n.x
645-- end))
646-- --> {{["x"]=1}, {["x"]=2}, {["x"]=3}}
647--
648-- @param array The array to inspect.
649-- @param iteratee The function invoked per iteration.
650-- @param selfArg The self binding of predicate.
651-- @return Returns the new duplicate-value-free array.
652_.uniq = function(array, iteratee, selfArg)
653    local t = {}
654    local results = {}
655    for k, v in ipairs(array) do
656        local r = callIteratee(iteratee, selfArg, v, k, array)
657        if _.indexOf(results, r) == -1 then
658            _.push(t, v)
659        end
660        _.push(results, r)
661    end
662    return t
663end
664
665---
666-- The inverse of _.pairs; this method returns an object composed from
667-- arrays of property names and values. Provide either a single two dimensional
668-- array, e.g. [[key1, value1], [key2, value2]] or two arrays, one of
669-- property names and one of corresponding values.
670-- @usage _.print(_.zipObject({{'fred', 30}, {'alex', 20}}))
671-- --> {["alex"]=20, ["fred"]=30}
672-- _.print(_.zipObject({'fred', 'alex'}, {30, 20}))
673-- --> {["alex"]=20, ["fred"]=30}
674--
675-- @param ... The properties/values
676-- @return Returns the new object.
677_.zipObject = function (...)
678    local tmp = _.table(...)
679    local t = {}
680    if #tmp == 1 then
681        for i, pair in ipairs(tmp[1]) do
682            t[pair[1]] = pair[2]
683        end
684    else
685        for i = 1, #tmp[1] do
686            t[tmp[1][i]] = tmp[2][i]
687        end
688    end
689    return t
690end
691
692
693---
694-- This method is like [_.zip](#_.zip) except that it accepts an array of grouped
695-- elements and creates an array regrouping the elements to their pre-zip
696-- configuration.
697-- @usage local t = _.zip({'a', 'b', 'c'}, {1, 2, 3}, {10, 20, 30})
698-- _.print(t)
699-- --> {{"a", 1, 10}, {"b", 2, 20}, {"c", 3, 30}}
700-- _.print(_.unzip(t))
701-- --> {{"a", "b", "c"}, {1, 2, 3}, {10, 20, 30}}
702--
703-- @param array The array of grouped elements to process.
704-- @return Returns the new array of regrouped elements.
705_.unzip = function (array)
706    return _.zip(_.args(array))
707end
708
709---
710-- Creates an array excluding all provided values
711-- @usage _.print(_.without({1,1, 2, 3, 2, 3, 5, 5, 1, 2},  5, 1))
712-- --> {2, 3, 2, 3, 2}
713--
714-- @param array The array to filter.
715-- @param ... The values to exclude.
716-- @return Returns the new array of filtered values.
717_.without = function (array, ...)
718    local t = {}
719    for i, v in ipairs(array) do
720        local args = _.table(...)
721        if _.indexOf(args, v) == -1 then
722            _.push(t, v)
723        end
724    end
725    return t
726end
727
728---
729-- Creates an array of grouped elements, the first of which contains
730-- the first elements of the given arrays, the second of which contains
731-- the second elements of the given arrays, and so on.
732-- @usage local t = _.zip({'a', 'b', 'c'}, {1, 2, 3}, {10, 20, 30})
733-- _.print(t)
734-- --> {{"a", 1, 10}, {"b", 2, 20}, {"c", 3, 30}}
735--
736-- @param ... The arrays to process
737-- @return Returns the new array of grouped elements.
738_.zip = function (...)
739    local t = {}
740    for i, array in ipairs(_.table(...)) do
741        for j, v in ipairs(array) do
742            t[j] = t[j] or {}
743            t[j][i] = v
744        end
745    end
746    return t
747end
748
749--- Collection
750-- @section Collection
751
752---
753-- Creates an array of elements corresponding to the given keys,
754-- or indexes, of collection. Keys may be specified as individual
755-- arguments or as arrays of keys.
756-- @usage _.print(_.at({'1', '2', '3', '4', a='a', b='b'}, {1, 2}, 'b'))
757-- --> {"1", "2", "b"}
758--
759-- @param collection The collection to iterate over.
760-- @param ... The property names or indexes of elements to pick,
761-- specified individually or in arrays.
762-- @return Return the new array of picked elements.
763_.at = function (collection, ...)
764    local t = {}
765    for k, key in ipairs(_.table(...)) do
766        if _.isTable(key) then
767            for k, key in ipairs(key) do
768                _.push(t, collection[key])
769            end
770        else
771            _.push(t, collection[key])
772        end
773    end
774    return t
775end
776
777---
778-- Creates an object composed of keys generated from the results of
779-- running each element of collection through iteratee. The corresponding
780-- value of each key is the number of times the key was returned by
781-- iteratee. The iteratee is bound to selfArg and invoked with three arguments:
782-- (value, index|key, collection).
783--
784-- @usage _.print(_.countBy({4.3, 6.1, 6.4}, function(n)
785--   return math.floor(n)
786-- end))
787-- --> {[4]=1, [6]=2}
788--
789-- @param collection The collection to iterate over. (table|string)
790-- @param[opt=_.identity] iteratee The function invoked per iteration.
791-- @param[opt] selfArg The self binding of predicate.
792-- @return Returns the composed aggregate object.
793_.countBy = function (collection, iteratee, selfArg)
794    local t = {}
795    for k, v in _.iter(collection) do
796        local r = _.str(
797            callIteratee(iteratee, selfArg, v, k, collection)
798        )
799        if _.isNil(t[r]) then
800            t[r] = 1
801        else
802            t[r] = t[r] + 1
803        end
804    end
805    return t
806end
807
808---
809-- Creates an object composed of keys generated from the results of
810-- running each element of collection through iteratee. The corresponding
811-- value of each key is an array of the elements responsible for generating
812-- the key. The iteratee is bound to selfArg and invoked with three arguments:
813-- (value, index|key, collection).
814-- @usage _.print(_.groupBy({4.3, 6.1, 6.4}, function(n)
815--   return math.floor(n)
816-- end))
817-- --> {[4]={4.3}, [6]={6.1, 6.4}}
818--
819-- @param collection The collection to iterate over. (table|string)
820-- @param[opt=_.identity] iteratee The function invoked per iteration.
821-- @param[opt] selfArg The self binding of predicate.
822-- @return Returns the composed aggregate object.
823_.groupBy = function (collection, iteratee, selfArg)
824    local t = {}
825    for k, v in _.iter(collection) do
826        local r = _.str(
827            callIteratee(iteratee, selfArg, v, k, collection)
828        )
829        if _.isNil(t[r]) then
830            t[r] = {v}
831        else
832            _.push(t[r], v)
833        end
834    end
835    return t
836end
837
838---
839-- Creates an object composed of keys generated from the results of
840-- running each element of collection through iteratee. The corresponding
841-- value of each key is the last element responsible for generating the key.
842-- The iteratee function is bound to selfArg and invoked with three arguments:
843-- (value, index|key, collection).
844-- @usage local keyData = {
845--     {dir='l', a=1},
846--     {dir='r', a=2}
847-- }
848-- _.print('40.indexBy          :', _.indexBy(keyData, function(n)
849--     return n.dir
850-- end))
851-- --> {["l"]={[a]=1, [dir]="l"}, ["r"]={[a]=2, [dir]="r"}}
852--
853-- @param collection The collection to iterate over. (table|string)
854-- @param[opt=_.identity] iteratee The function invoked per iteration.
855-- @param[opt] selfArg The self binding of predicate.
856-- @return Returns the composed aggregate object.
857_.indexBy = function (collection, iteratee, selfArg)
858    local t = {}
859    for k, v in _.iter(collection) do
860        local r = _.str(
861            callIteratee(iteratee, selfArg, v, k, collection)
862        )
863        t[r] = v
864    end
865    return t
866end
867
868---
869-- Checks if predicate returns truthy for all elements of collection.
870-- The predicate is bound to selfArg and invoked with three arguments:
871-- (value, index|key, collection).
872-- @usage _.print(_.every({1, 2, 3, 4, '5', 6}, _.isNumber))
873-- --> false
874-- _.print(_.every({1, 2, 3, 4, 5, 6}, _.isNumber))
875-- --> true
876--
877-- @param collection The collection to iterate over. (table|string)
878-- @param[opt=_.identity] predicate The function invoked per iteration
879-- @param[opt] selfArg The self binding of predicate.
880_.every = function (collection, predicate, selfArg)
881    for k, v in _.iter(collection) do
882        if not callIteratee(predicate, selfArg, v, k, collection) then
883            return false
884        end
885    end
886    return true
887end
888
889local filter = function(collection, predicate, selfArg, reject)
890    local t = {}
891    for k, v in _.iter(collection) do
892        local check = callIteratee(predicate, selfArg, v, k, collection)
893        if reject then
894            if not check then
895                _.push(t, v)
896            end
897        else
898            if check then
899                _.push(t, v)
900            end
901        end
902    end
903    return t
904end
905
906---
907-- Iterates over elements of collection, returning an array of all
908-- elements predicate returns truthy for. The predicate is bound to
909-- selfArg and invoked with three arguments: (value, index|key, collection).
910-- @usage _.print(_.filter({1, 2, 3, 4, '5', 6, '7'}, _.isNumber))
911-- --> {1, 2, 3, 4, 6}
912--
913-- @param collection The collection to iterate over. (table|string)
914-- @param[opt=_.identity] predicate The function invoked per iteration
915-- @param[opt] selfArg The self binding of predicate.
916_.filter = function (collection, predicate, selfArg)
917    return filter(collection, predicate, selfArg)
918end
919
920---
921-- Iterates over elements of collection invoking iteratee for each element.
922-- The iteratee is bound to selfArg and invoked with three arguments:
923-- (value, index|key, collection). Iteratee functions may exit iteration
924-- early by explicitly returning false.
925--
926-- @param collection The collection to iterate over. (table|string)
927-- @param[opt=_.identity] predicate The function invoked per iteration
928-- @param[opt] selfArg The self binding of predicate.
929-- @return Returns collection.
930_.forEach = function (collection, predicate, selfArg)
931    for k, v in _.iter(collection) do
932        callIteratee(predicate, selfArg, v, k, collection)
933    end
934    return collection
935end
936
937---
938-- This method is like [_.forEach](#_.forEach) except that it iterates
939-- over elements of collection from right to left.
940--
941-- @param collection The collection to iterate over. (table|string)
942-- @param[opt=_.identity] predicate The function invoked per iteration
943-- @param[opt] selfArg The self binding of predicate.
944-- @return Returns collection.
945_.forEachRight = function (collection, predicate, selfArg)
946    for k, v in _.iterRight(collection) do
947        callIteratee(predicate, selfArg, v, k, collection)
948    end
949    return collection
950end
951
952---
953-- Checks if target is in collection.
954-- @usage print(_.includes({1, 2, 'x', 3, ['5']=4, x=3, 5}, 'x'))
955-- --> true
956-- print(_.includes({1, 2, 'x', 3, ['5']=4, x=3, 5}, 'z'))
957-- --> false
958-- @param collection The collection to search
959-- @param target The value to search for.
960_.includes = function (collection, target)
961    local result = _.find(collection, function (n)
962        return n == target
963    end)
964    return result ~= nil
965end
966
967---
968-- Invokes method of each element in collection, returning an array of the
969-- results of each invoked method. Any additional arguments are provided
970-- to each invoked method. func bound to, each element in collection.
971-- @usage _.print(_.invoke({'1.first', '2.second', '3.third'}, string.sub, 1, 1))
972-- --> {"1", "2", "3"}
973--
974-- @param collection The collection to iterate over.
975-- @param method The method to invoke per iteration.
976-- @param ... The arguments to invoke the method with.
977-- @return Returns the array of results.
978_.invoke = function (collection, method, ...)
979    local t = {}
980    for k, v in _.iter(collection) do
981        _.push(t, callIteratee(method, v, ...))
982    end
983    return t
984end
985
986---
987-- Creates an array of values by running each element in collection through
988-- iteratee. The iteratee is bound to selfArg and invoked with three
989-- arguments: (value, index|key, collection).
990-- @usage _.print(_.map({1, 2, 3, 4, 5, 6, 7, 8, 9}, function(n)
991--     return n * n
992-- end))
993-- --> {1, 4, 9, 16, 25, 36, 49, 64, 81}
994--
995-- @param collection The collection to iterate over. (table|string)
996-- @param[opt=_.identity] iteratee The function invoked per iteration
997-- @param[opt] selfArg The self binding of predicate.
998_.map = function (collection, iteratee, selfArg)
999    local t = {}
1000    for k, v in _.iter(collection) do
1001        t[k] = callIteratee(iteratee, selfArg, v, k, collection)
1002    end
1003    return t
1004end
1005
1006---
1007-- Creates an array of elements split into two groups, the first of
1008-- which contains elements predicate returns truthy for, while the second
1009-- of which contains elements predicate returns falsey for. The predicate
1010-- is bound to selfArg and invoked with three arguments:
1011-- (value, index|key, collection).
1012-- @usage _.print(_.partition({1, 2, 3, 4, 5, 6, 7}, function (n)
1013--     return n > 3
1014-- end))
1015-- --> {{4, 5, 6, 7}, {1, 2, 3}}
1016--
1017-- @param collection The collection to iterate over. (table|string)
1018-- @param[opt=_.identity] predicate The function invoked per iteration
1019-- @param[opt] selfArg The self binding of predicate.
1020-- @return  Returns the array of grouped elements.
1021_.partition = function (collection, predicate, selfArg)
1022    local t = {{}, {}}
1023    for k, v in _.iter(collection) do
1024        if callIteratee(predicate, selfArg, v, k, collection) then
1025            _.push(t[1], v)
1026        else
1027            _.push(t[2], v)
1028        end
1029    end
1030    return t
1031end
1032
1033---
1034-- Gets the property value of path from all elements in collection.
1035-- @usage local users = {
1036--   { user = 'barney', age = 36, child = {age = 5}},
1037--   { user = 'fred',   age = 40, child = {age = 6} }
1038-- }
1039-- _.print(_.pluck(users, {'user'}))
1040-- --> {"barney", "fred"}
1041-- _.print(_.pluck(users, {'child', 'age'}))
1042-- --> {5, 6}
1043--
1044-- @param collection The collection to iterate over.
1045-- @param path The path of the property to pluck.
1046_.pluck = function (collection, path)
1047    local t = {}
1048    for k, value in _.iter(collection) do
1049        _.push(t, _.get(value, path))
1050    end
1051    return t
1052end
1053
1054
1055---
1056-- Reduces collection to a value which is the accumulated result of
1057-- running each element in collection through iteratee, where each
1058-- successive invocation is supplied the return value of the previous.
1059-- If accumulator is not provided the first element of collection is used
1060--  as the initial value. The iteratee is bound to selfArg and invoked
1061-- with four arguments: (accumulator, value, index|key, collection).
1062-- @usage _.print(_.reduce({1, 2, 3}, function(total, n)
1063--   return n + total;
1064-- end))
1065-- --> 6
1066-- _.print(_.reduce({a = 1, b = 2}, function(result, n, key)
1067--     result[key] = n * 3
1068--     return result;
1069-- end, {}))
1070-- --> {["a"]=3, ["b"]=6}
1071--
1072-- @param collection The collection to iterate over.
1073-- @param[opt=_.identity] iteratee The function invoked per iteration.
1074-- @param[opt=<first element>] accumulator The initial value.
1075-- @param[opt] selfArg The self binding of predicate.
1076-- @return Returns the accumulated value.
1077_.reduce = function (collection, iteratee, accumulator, selfArg)
1078    local accumulator = accumulator
1079    for k, v in _.iter(collection) do
1080        if _.isNil(accumulator) then
1081            accumulator = v
1082        else
1083            accumulator =  callIteratee(iteratee, selfArg, accumulator, v, k, collection)
1084        end
1085    end
1086    return accumulator
1087end
1088
1089---
1090-- This method is like _.reduce except that it iterates over elements
1091-- of collection from right to left.
1092-- @usage local array = {0, 1, 2, 3, 4, 5};
1093-- _.print(_.reduceRight(array, function(str, other)
1094--   return str .. other
1095-- end, ''))
1096-- --> 543210
1097--
1098-- @param collection The collection to iterate over.
1099-- @param[opt=_.identity] iteratee The function invoked per iteration.
1100-- @param[opt=<first element>] accumulator The initial value.
1101-- @param[opt] selfArg The self binding of predicate.
1102-- @return Returns the accumulated value.
1103_.reduceRight = function (collection, iteratee, accumulator, selfArg)
1104    local accumulator = accumulator
1105    for k, v in _.iterRight(collection) do
1106        if _.isNil(accumulator) then
1107            accumulator = v
1108        else
1109            accumulator =  callIteratee(iteratee, selfArg, accumulator, v, k, collection)
1110        end
1111    end
1112    return accumulator
1113end
1114
1115---
1116-- The opposite of [_.filter](#_.filter); this method returns the elements of
1117-- collection that predicate does not return truthy for.
1118-- @usage _.print(_.reject({1, 2, 3, 4, '5', 6, '7'}, _.isNumber))
1119-- --> {"5", "7"}
1120--
1121-- @param collection The collection to iterate over. (table|string)
1122-- @param[opt=_.identity] predicate The function invoked per iteration
1123-- @param[opt] selfArg The self binding of predicate.
1124_.reject = function (collection, predicate, selfArg)
1125    return filter(collection, predicate, selfArg, true)
1126end
1127
1128---
1129-- Gets a random element or n random elements from a collection.
1130-- @usage _.print(_.sample({1, 2, 3, a=4, b='x', 5, 23, 24}, 4))
1131-- --> {5, "x", 1, 23}
1132-- _.print(_.sample({1, 2, 3, a=4, b='x', 5, 23, 24}))
1133-- --> 4
1134--
1135-- @param collection The collection to sample.
1136-- @param[opt=1] n The number of elements to sample.
1137-- @return Returns the random sample(s).
1138_.sample = function (collection, n)
1139    local n = n or 1
1140    local t = {}
1141    local keys = _.keys(collection)
1142    for i=1, n do
1143        local pick = keys[_.random(1, #keys)]
1144        _.push(t, _.get(collection, {pick}))
1145    end
1146    return #t == 1 and t[1] or t
1147end
1148
1149---
1150-- Gets the size of collection by returning its length for array-like
1151-- values or the number of own enumerable properties for objects.
1152-- @usage _.print(_.size({'abc', 'def'}))
1153-- --> 2
1154-- _.print(_.size('abcdefg'))
1155-- --> 7
1156-- _.print(_.size({a=1, b=2,c=3}))
1157-- --> 3
1158--
1159-- @param collection The collection to inspect.
1160-- @return Returns the size of collection.
1161_.size = function (collection)
1162    local c = 0
1163    for k, v in _.iter(collection) do
1164        c = c + 1
1165    end
1166    return c
1167end
1168
1169---
1170-- Checks if predicate returns truthy for any element of collection.
1171-- The function returns as soon as it finds a passing value and does
1172-- not iterate over the entire collection. The predicate is bound to
1173-- selfArg and invoked with three arguments: (value, index|key, collection).
1174--
1175-- @usage _.print(_.some({1, 2, 3, 4, 5, 6}, _.isString))
1176-- --> false
1177-- _.print(_.some({1, 2, 3, 4, '5', 6}, _.isString))
1178-- --> true
1179-- @param collection The collection to iterate over. (table|string)
1180-- @param[opt=_.identity] predicate The function invoked per iteration
1181-- @param[opt] selfArg The self binding of predicate.
1182-- @return Returns true if any element passes the predicate check, else false.
1183_.some = function (collection, predicate, selfArg)
1184    for k, v in _.iter(collection) do
1185        if callIteratee(predicate, selfArg, v, k, collection) then
1186            return true
1187        end
1188    end
1189    return false
1190end
1191
1192---
1193-- Creates an array of elements, sorted in ascending order by the
1194-- results of running each element in a collection through iteratee.
1195-- The iteratee is bound to selfArg and
1196-- invoked with three arguments: (value, index|key, collection).
1197-- @usage local t = {1, 2, 3}
1198-- _.print(_.sortBy(t, function (a)
1199--     return math.sin(a)
1200-- end))
1201-- --> {1, 3, 2}
1202-- local users = {
1203--     { user='fred' },
1204--     { user='alex' },
1205--     { user='zoee' },
1206--     { user='john' },
1207-- }
1208-- _.print(_.sortBy(users, function (a)
1209--     return a.user
1210-- end))
1211-- --> {{["user"]="alex"}, {["user"]="fred"}, {["user"]="john"}, {["user"]="zoee"}}
1212--
1213-- @param collection The collection to iterate over.
1214-- @param[opt=_.identity] predicate The function invoked per iteration
1215-- @param[opt] selfArg The self binding of predicate.
1216-- @return  Returns the new sorted array.
1217_.sortBy = function (collection, predicate, selfArg)
1218    local t ={}
1219    local empty = true
1220    local previous
1221    for k, v in _.iter(collection) do
1222        if empty then
1223            _.push(t, v)
1224            previous = callIteratee(predicate, selfArg, v, k, collection)
1225            empty = false
1226        else
1227            local r = callIteratee(predicate, selfArg, v, k, collection)
1228            if _.lt(previous, r) then
1229                table.insert(t, v)
1230                previous = r
1231            else
1232                table.insert(t, #t, v)
1233            end
1234        end
1235    end
1236    return t
1237end
1238
1239---
1240-- Iterates over elements of collection, returning the first element
1241-- predicate returns truthy for. The predicate is bound to selfArg and
1242-- invoked with three arguments: (value, index|key, collection).
1243-- @usage _.print(_.find({{a = 1}, {a = 2}, {a = 3}, {a = 2}, {a = 3}}, function(v)
1244--     return v.a == 3
1245-- end))
1246-- --> {[a]=3}
1247--
1248-- @param collection The collection to search. (table|string)
1249-- @param predicate The function invoked per iteration
1250-- @param selfArg The self binding of predicate.
1251_.find = function (collection, predicate, selfArg)
1252    for k, v in _.iter(collection) do
1253        if callIteratee(predicate, selfArg, v, k, collection) then
1254            return v
1255        end
1256    end
1257end
1258
1259---
1260-- This method is like _.find except that it iterates over elements of
1261-- collection from right to left.
1262-- @usage _.findLast({{a = 1}, {a = 2}, {a = 3, x = 1}, {a = 2}, {a = 3, x = 2}},
1263-- function(v)
1264--     return v.a == 3
1265-- end))
1266-- --> {[a]=3, [x]=2}
1267--
1268-- @param collection The collection to search. (table|string)
1269-- @param predicate The function invoked per iteration
1270-- @param selfArg The self binding of predicate.
1271_.findLast = function (collection, predicate, selfArg)
1272    for k, v in _.iterRight(collection) do
1273        if callIteratee(predicate, selfArg, v, k, collection) then
1274            return v
1275        end
1276    end
1277end
1278
1279--- Function
1280-- @section Function
1281
1282---
1283-- This method creates a function that invokes func once it’s called n
1284--  or more times.
1285-- @usage local printAfter3 = _.after(3, print)
1286-- for i = 1, 5 do
1287--    printAfter3('done', i)
1288-- end
1289-- --> done 4
1290-- --> done 5
1291--
1292-- @param n The number of calls before func invoked.
1293-- @param func The function to restrict.
1294-- @return Returns the new restricted function.
1295_.after = function(n, func)
1296    local i = 1
1297    return function(...)
1298        if _.gt(i, n) then
1299            return func(...)
1300        end
1301        i = i + 1
1302    end
1303end
1304
1305---
1306-- Creates a function that accepts up to n arguments ignoring any
1307-- additional arguments.
1308-- @usage local printOnly3 =_.ary(print, 3)
1309-- printOnly3(1, 2, 3, 'x', 'y', 6)
1310-- --> 1    2   3
1311--
1312-- @param func The function to cap arguments for.
1313-- @param n the arity cap.
1314-- @return Returns the new function
1315_.ary = function(func, n)
1316    return function(...)
1317        if n == 1 then
1318            return func((...))
1319        else
1320            local t = _.table(...)
1321            local first = _.take(t, n)
1322            return func(_.args(first))
1323        end
1324    end
1325end
1326
1327---
1328-- Creates a function that invokes func while it’s called less than n times.
1329-- Subsequent calls to the created function return the result of the
1330-- last func invocation.
1331-- @usage local printBefore3 = _.before(3, print)
1332-- for i = 1, 10 do
1333--     printBefore3(i, 'ok')
1334-- end
1335-- -->  1   ok
1336-- -->  2   ok
1337-- -->  3   ok
1338--
1339-- @param n The number of calls at which func is no longer invoked.
1340-- @param func The function to restrict.
1341-- @return Returns the new restriced function.
1342_.before = function (n, func)
1343    local i = 1
1344    local result
1345    return function (...)
1346        if _.lte(i, n) then
1347            result = func(...)
1348        end
1349        i = i + 1
1350        return result
1351    end
1352end
1353
1354---
1355-- Creates a function that runs each argument through a corresponding
1356-- transform function.
1357-- @usage local increment = function(...)
1358--     return _.args(_.map(_.table(...), function(n)
1359--         return n + 1
1360--     end))
1361-- end
1362-- local pow = function(...)
1363--     return _.args(_.map(_.table(...), function(n)
1364--         return n * n
1365--     end))
1366-- end
1367-- local modded = _.modArgs(function(...)
1368--     print(...)
1369-- end, {increment, increment}, pow)
1370-- modded(0, 1, 2)
1371-- -->  4   9   16
1372--
1373-- @param func The function to wrap
1374-- @param ... The functions to transform arguments, specified as
1375-- individual functions or arrays of functions.
1376-- @return Returns the new function.
1377_.modArgs = function (func, ...)
1378    local transforms = {}
1379    for i, v in ipairs( _.table(...)) do
1380        if _.isFunction(v) then
1381            _.push(transforms, v)
1382        elseif _.isTable(v) then
1383            for k2, v2 in _.iter(v) do
1384                if _.isFunction(v2) then _.push(transforms, v2) end
1385            end
1386        end
1387    end
1388    return function(...)
1389        local args
1390        for i, transform in ipairs(transforms) do
1391            if _.isNil(args) then
1392                args = _.table(transform(...))
1393            else
1394                args = _.table(transform(_.args(args)))
1395            end
1396        end
1397        if _.isNil(args) then
1398            return func(...)
1399        else
1400            return func(_.args(args))
1401        end
1402    end
1403end
1404
1405---
1406-- Creates a function that negates the result of the predicate func.
1407-- The func predicate is invoked with arguments of the created function.
1408-- @usage local isEven = function (n)
1409--     return n % 2 == 0
1410-- end
1411-- local isOdd = _.negate(isEven)
1412-- _.print(_.filter({1, 2, 3, 4, 5, 6}, isEven))
1413-- --> {2, 4, 6}
1414-- _.print(_.filter({1, 2, 3, 4, 5, 6}, isOdd))
1415-- --> {1, 3, 5}
1416--
1417-- @param func The preadicate to negate.
1418-- @return Returns the new function
1419_.negate = function (func)
1420    return function(...)
1421        return not func(...)
1422    end
1423end
1424
1425---
1426-- Creates a function that is restricted to invoking func once. Repeat
1427-- calls to the function return the value of the first call. The func
1428-- is invoked with arguments of the created function.
1429-- @usage local createApp = function(version)
1430--     print('App created with version '..version)
1431--     return version
1432-- end
1433-- local initialize = _.once(createApp)
1434-- initialize(1.1)
1435-- initialize(1.1)
1436-- initialize(1.1)
1437-- --> App created with version 1.1
1438-- --> 1.1
1439-- --> 1.1
1440-- --> 1.1
1441--
1442-- @param func The function to restrict.
1443-- @return Returns the new function.
1444_.once = function (func)
1445    local called = false;
1446    local result
1447    return function(...)
1448        if not called then
1449            result = func(...)
1450            called = true
1451        end
1452        return result
1453    end
1454end
1455
1456
1457---
1458-- Creates a function that invokes func with arguments arranged according
1459-- to the specified indexes where the argument value at the first index
1460-- is provided as the first argument, the argument value at the second
1461-- index is provided as the second argument, and so on.
1462-- @usage local rearged = _.rearg(function(a, b, c)
1463--   return {a, b, c};
1464-- end, 2, 1, 3)
1465-- _.print(rearged('a', 'b', 'c'))
1466-- --> {"b", "a", "c"}
1467-- _.print(rearged('b', 'a', 'c'))
1468-- --> {"a", "b", "c"}
1469--
1470-- @param func The function to rearrange arguments for.
1471-- @param ... The arranged argument indexes, specified as individual
1472-- indexes or arrays of indexes.
1473-- @return Returns the new function.
1474_.rearg = function (func, ...)
1475    local indexes = {}
1476    for i, v in ipairs(_.table(...)) do
1477        if _.isNumber(v) then
1478            _.push(indexes, v)
1479        elseif _.isTable(v) then
1480            for k2, v2 in _.iter(v) do
1481                if _.isNumber(v2) then _.push(indexes, v2) end
1482            end
1483        end
1484    end
1485    return function(...)
1486        local args = _.table(...)
1487        local newArgs = {}
1488        for i, index in ipairs(indexes) do
1489            _.push(newArgs, args[index])
1490        end
1491        if #indexes == 0 then
1492            return func(...)
1493        else
1494            return func(_.args(newArgs))
1495        end
1496    end
1497end
1498
1499
1500
1501--- Lang
1502-- @section Lang
1503---
1504
1505---
1506-- Cast value to arguments
1507-- @usage print(_.args({1, 2, 3}))
1508-- --> 1    2   3
1509--
1510-- @param value value to cast
1511-- @return Returns arguments
1512_.args = function (value)
1513    if _.isTable(value) then return table.unpack(value)
1514    else return table.unpack({value})
1515    end
1516end
1517
1518---
1519-- Checks if value is greater than other.
1520-- @usage _.print(_.gt(1, 3))
1521-- --> false
1522-- _.print(_.gt(4, 3))
1523-- --> true
1524--
1525-- @param value The value to compare.
1526-- @param other The other value to compare.
1527_.gt = function (value, other, ...)
1528    local value, other = _.cast(value, other)
1529    if _.isString(value) or _.isNumber(value) then
1530        return value > other
1531    elseif _.isFunction(value) then
1532        return value(...) > other(...)
1533    end
1534    return false
1535end
1536
1537---
1538-- Checks if value is greater than other.
1539-- @usage _.print(_.gte(1, 3))
1540-- --> false
1541-- _.print(_.gte(3, 3))
1542-- --> true
1543--
1544-- @param value The value to compare.
1545-- @param other The other value to compare.
1546_.gte = function (value, other, ...)
1547    if _.isNil(value) or _.isBoolean(value) then
1548        return value == other
1549    end
1550    local value, other = _.cast(value, other)
1551    if _.isString(value) or _.isNumber(value) then
1552        return value >= other
1553    elseif _.isFunction(value) then
1554        return value(...) >= other(...)
1555    elseif _.isTable(value) then
1556        return false
1557    end
1558    return false
1559end
1560
1561---
1562-- Checks if value is classified as a boolean primitive.
1563-- @usage _.print(_.isBoolean(false))
1564-- --> true
1565-- _.print(_.isBoolean('x'))
1566-- --> false
1567--
1568-- @param value the value to check
1569-- @return Returns true if value is correctly classified, else false.
1570_.isBoolean = function(value)
1571    return type(value) == 'boolean'
1572end
1573
1574---
1575-- Checks if value is empty. A value is considered empty unless it’s an
1576-- arguments table, array, string with a length greater than 0 or an
1577--object with own enumerable properties.
1578--@usage _.print(_.isEmpty(true))
1579-- --> true
1580-- _.print(_.isEmpty(1))
1581-- --> true
1582-- _.print(_.isEmpty({1, 2, 3}))
1583-- --> false
1584-- _.print(_.isEmpty({a= 1}))
1585-- --> false
1586--
1587-- @param value The value to inspect.
1588-- @return Returns true if value is empty, else false.
1589_.isEmpty = function (value)
1590    if _.isString(value) then
1591        return #value == 0
1592    elseif _.isTable(value) then
1593        local i = 0
1594        for k, v in _.iter(value) do
1595            i = i + 1
1596        end
1597        return i == 0
1598    else
1599        return true
1600    end
1601end
1602
1603---
1604-- Checks if parm1 and parm2 are equal. Parm can be a boolean, string, number, function or table
1605---
1606--@usage _.print(_.isEqual(true))
1607-- --> true
1608-- _.print(_.isEmpty(1))
1609-- --> true
1610-- _.print(_.isEmpty({1, 2, 3}))
1611-- --> false
1612-- _.print(_.isEmpty({a= 1}))
1613-- --> false
1614--
1615-- @param parm1, parm2 The values to compare
1616-- @return Returns true if values are equal, else false.
1617
1618_.isEqual = function (parm1, parm2)
1619    local avoid_loops = {}
1620    local function recurse(t1, t2)
1621        if type(t1) ~= type(t2) then return false end
1622        if type(t1) ~= "table" then return t1 == t2 end
1623        if avoid_loops[t1] then return avoid_loops[t1] == t2 end
1624        avoid_loops[t1] = t2
1625        local t2keys = {}
1626        local t2tablekeys = {}
1627        for k, _ in pairs(t2) do
1628            if type(k) == "table" then table.insert(t2tablekeys, k) end
1629            t2keys[k] = true
1630        end
1631        for k1, v1 in pairs(t1) do
1632            local v2 = t2[k1]
1633            if type(k1) == "table" then
1634                local ok = false
1635                for i, tk in ipairs(t2tablekeys) do
1636                    if _.isEqual(k1, tk) and recurse(v1, t2[tk]) then
1637                        table.remove(t2tablekeys, i)
1638                        t2keys[tk] = nil
1639                        ok = true
1640                        break
1641                    end
1642                end
1643                if not ok then return false end
1644            else
1645                if v2 == nil then return false end
1646                t2keys[k1] = nil
1647                if not recurse(v1, v2) then return false end
1648            end
1649        end
1650        if next(t2keys) then return false end
1651        return true
1652    end
1653    return recurse(parm1, parm2)
1654end
1655
1656
1657---
1658-- Checks if value is classified as a function primitive.
1659-- @usage _.print(_.isFunction(function() end))
1660-- --> true
1661-- _.print(_.isFunction(1))
1662-- --> false
1663--
1664-- @param value the value to check
1665-- @return Returns true if value is correctly classified, else false.
1666_.isFunction = function(value)
1667    return type(value) == 'function'
1668end
1669
1670---
1671-- Checks if value is classified as a nil primitive.
1672-- @usage _.print(_.isNil(variable)
1673-- --> true
1674-- variable = 1
1675-- _.print(_.isNil(variable))
1676-- --> false
1677--
1678-- @param value the value to check
1679-- @return Returns true if value is correctly classified, else false.
1680_.isNil = function(value)
1681    return type(value) == 'nil'
1682end
1683
1684---
1685-- Checks if value is classified as a number primitive.
1686-- @usage _.print(_.isNumber(1))
1687-- --> true
1688-- _.print(_.isNumber('1'))
1689-- --> false
1690--
1691-- @param value the value to check
1692-- @return Returns true if value is correctly classified, else false.
1693_.isNumber = function(value)
1694    return type(value) == 'number'
1695end
1696
1697---
1698-- Checks if value is classified as a string primitive.
1699-- @usage _.print(_.isString('1'))
1700-- --> true
1701-- _.print(_.isString(1))
1702-- --> false
1703--
1704-- @param value the value to check
1705-- @return Returns true if value is correctly classified, else false.
1706_.isString = function(value)
1707    return type(value) == 'string'
1708end
1709
1710---
1711-- Checks if value is classified as a table primitive.
1712-- @usage _.print(_.isTable({'1'}))
1713-- --> true
1714-- _.print(_.isString(1))
1715-- --> false
1716--
1717-- @param value the value to check
1718-- @return Returns true if value is correctly classified, else false.
1719_.isTable = function(value)
1720    return type(value) == 'table'
1721end
1722
1723-- local implicitCast function (...)
1724--     if
1725-- end
1726
1727---
1728-- Checks if value is less than other.
1729-- @usage _.print(_.lt(1, 3))
1730-- --> true
1731-- _.print(_.lt(3, 3))
1732-- --> false
1733--
1734-- @param value The value to compare.
1735-- @param other The other value to compare.
1736_.lt = function (value, other, ...)
1737    local value, other = _.cast(value, other)
1738    if _.isString(value) or _.isNumber(value) then
1739        return value < other
1740    elseif _.isFunction(value) then
1741        return value(...) < other(...)
1742    end
1743    return false
1744end
1745
1746---
1747-- Checks if value is less than or euqal to other.
1748-- @usage _.print(_.lt(4, 3))
1749-- --> false
1750-- _.print(_.lt(3, 3))
1751-- --> true
1752-- @param value The value to compare.
1753-- @param other The other value to compare.
1754_.lte = function (value, other, ...)
1755    if _.isNil(value) or _.isBoolean(value) then
1756        return value == other
1757    end
1758    local value, other = _.cast(value, other)
1759    if _.isString(value) or _.isNumber(value) then
1760        return value <= other
1761    elseif _.isFunction(value) then
1762        return value(...) <= other(...)
1763    elseif _.isTable(value) then
1764        return false
1765    end
1766    return false
1767end
1768
1769_.cast = function (a, b)
1770    if type(a) == type(b) then return a, b end
1771    local cast
1772    if _.isString(a) then cast = _.str
1773    elseif _.isBoolean(a) then cast = _.bool
1774    elseif _.isNumber(a) then cast = _.num
1775    elseif _.isFunction(a) then cast = _.func
1776    elseif _.isTable(a) then cast = _.table
1777    end
1778    return a, cast(b)
1779end
1780
1781---
1782-- Cast parameters to a function that return passed parameters.
1783-- @usage local f = _.func(1, 2, 3)
1784-- _.print(f())
1785-- --> 1    2   3
1786--
1787-- @param value value to cast
1788-- @param ... The parameters to pass to any detected function
1789-- @return casted value
1790_.func = function (...)
1791    local t = _.table(...)
1792    return function ()
1793        return _.args(t)
1794    end
1795end
1796
1797---
1798-- Cast parameters to table using table.pack
1799-- @usage print(_.table(1, 2, 3))
1800-- --> {1, 2, 3}
1801-- print(_.table("123"))
1802-- --> {"123"}
1803-- print(_.table(0))
1804-- --> {0}
1805--
1806-- @param value value to cast
1807-- @param ... The parameters to pass to any detected function
1808-- @return casted value
1809_.table = function (...)
1810    return table.pack(...)
1811end
1812
1813---
1814-- Cast anything to boolean. If any function detected, call and cast its
1815-- result. Return false for 0, nil, table and empty string.
1816-- @usage print(_.bool({1, 2, 3}))
1817-- --> false
1818-- print(_.bool("123"))
1819-- --> true
1820-- print(_.bool(0))
1821-- --> false
1822-- print(_.bool(function(a) return a end, "555"))
1823-- --> true
1824--
1825-- @param value value to cast
1826-- @param ... The parameters to pass to any detected function
1827-- @return casted value
1828_.bool = function (value, ...)
1829    local bool = false
1830    if _.isString(value) then
1831        bool = #value > 0
1832    elseif _.isBoolean(value) then
1833        bool = value
1834    elseif _.isNumber(value) then
1835        bool = value ~= 0
1836    elseif _.isFunction(value) then
1837        bool = _.bool(value(...))
1838    end
1839    return bool
1840end
1841
1842---
1843-- Cast anything to number. If any function detected, call and cast its
1844-- result. Return 0 for nil and table.
1845-- @usage print(_.num({1, 2, 3}))
1846-- --> 0
1847-- print(_.num("123"))
1848-- --> 123
1849-- print(_.num(true))
1850-- --> 1
1851-- print(_.num(function(a) return a end, "555"))
1852-- --> 555
1853--
1854-- @param value value to cast
1855-- @param ... The parameters to pass to any detected function
1856-- @return casted value
1857_.num = function (value, ...)
1858    local num = 0
1859    if _.isString(value) then
1860        ok = pcall(function()
1861            num = value + 0
1862        end)
1863        if not ok then
1864            num = math.huge
1865        end
1866    elseif _.isBoolean(value) then
1867        num = value and 1 or 0
1868    elseif _.isNumber(value) then
1869        num = value
1870    elseif _.isFunction(value) then
1871        num = _.num(value(...))
1872    end
1873    return num
1874end
1875
1876
1877local dblQuote = function (v)
1878    return '"'..v..'"'
1879end
1880
1881---
1882-- Cast anything to string. If any function detected, call and cast its
1883-- result.
1884-- @usage print(_.str({1, 2, 3, 4, {k=2, {'x', 'y'}}}))
1885-- --> {1, 2, 3, 4, {{"x", "y"}, ["k"]=2}}
1886-- print(_.str({1, 2, 3, 4, function(a) return a end}, 5))
1887-- --> {1, 2, 3, 4, 5}
1888--
1889-- @param value value to cast
1890-- @param ... The parameters to pass to any detected function
1891-- @return casted value
1892_.str = function (value, ...)
1893    local str = '';
1894    -- local v;
1895    if _.isString(value) then
1896        str = value
1897    elseif _.isBoolean(value) then
1898        str = value and 'true' or 'false'
1899    elseif _.isNil(value) then
1900        str = 'nil'
1901    elseif _.isNumber(value) then
1902        str = value .. ''
1903    elseif _.isFunction(value) then
1904        str = _.str(value(...))
1905    elseif _.isTable(value) then
1906        str = '{'
1907        for k, v in pairs(value) do
1908            v = _.isString(v) and dblQuote(v) or _.str(v, ...)
1909            if _.isNumber(k) then
1910                str = str .. v .. ', '
1911            else
1912                str = str .. '[' .. dblQuote(k) .. ']=' .. v .. ', '
1913            end
1914        end
1915        str = str:sub(0, #str - 2) .. '}'
1916    end
1917    return str
1918end
1919
1920
1921--- Number
1922-- @section Number
1923
1924---
1925-- Checks if n is between start and up to but not including, end.
1926-- If end is not specified it’s set to start with start then set to 0.
1927-- @usage print(_.inRange(-3, -4, 8))
1928-- --> true
1929--
1930-- @param n The number to check.
1931-- @param start The start of the range.
1932-- @param stop The end of the range.
1933-- @return Returns true if n is in the range, else false.
1934_.inRange = function (n, start, stop)
1935    local _start = _.isNil(stop) and 0 or start or 0
1936    local _stop = _.isNil(stop) and start or stop or 1
1937    return n >= _start and n < _stop
1938end
1939
1940---
1941-- Produces a random number between min and max (inclusive).
1942-- If only one argument is provided a number between 0 and the given
1943-- number is returned. If floating is true, a floating-point number is
1944-- returned instead of an integer.
1945-- @usage _.print(_.random())
1946-- --> 1
1947-- _.print(_.random(5))
1948-- --> 3
1949-- _.print(_.random(5, 10, true))
1950-- --> 8.8120200577248
1951--
1952-- @param[opt=0] min the minimum possible value.
1953-- @param[opt=1] max the maximum possible value.
1954-- @param[opt=false] floating Specify returning a floating-point number.
1955-- @return Returns the random number.
1956_.random = function (min, max, floating)
1957    local minim = _.isNil(max) and 0 or min or 0
1958    local maxim = _.isNil(max) and min or max or 1
1959    math.randomseed(os.clock() * math.random(os.time()))
1960    local r = math.random(minim, maxim)
1961    if floating then
1962        r = r + math.random()
1963    end
1964    return r
1965end
1966
1967---
1968-- Rounds a float number to the required number of decimals
1969-- If only one argument is provided it's round to an integer
1970-- @usage _print(_.round(math.pi)
1971-- --> 3
1972-- _.print(_.round(math.pi, 2)
1973-- --> 3.14
1974--
1975-- @param the float to convert
1976-- @param[opt=1] the number of deceimals to round to
1977-- @return Returns the round number.
1978_.round = function (x, n)
1979    x = tonumber(x)
1980    if not(_.isNumber(x)) then return x end
1981    n = 10^(n or 0)
1982	x = x * n
1983	if x >= 0 then
1984		x = math.floor(x + 0.5)
1985	else
1986		x = math.ceil(x - 0.5)
1987	end
1988	return x / n
1989end
1990
1991
1992--- Object
1993-- @section Object
1994
1995---
1996-- Gets the property value at path of object. If the resolved value
1997-- is nil the defaultValue is used in its place.
1998-- @usage local object = {a={b={c={d=5}}}}
1999-- _.print(_.get(object, {'a', 'b', 'c', 'd'}))
2000-- --> 5
2001--
2002-- @param object The object to query.
2003-- @param path The path of the property to get.
2004-- @param[opt=nil] defaultValue The value returned if the resolved value is nil.
2005-- @return Returns the resolved value.
2006_.get = function (object, path, defaultValue)
2007    if _.isTable(object) then
2008        local value = object
2009        local c = 1
2010        while not _.isNil(path[c]) do
2011            if not _.isTable(value) then return defaultValue end
2012            value = value[path[c]]
2013            c = c + 1
2014        end
2015        return value or defaultValue
2016    elseif _.isString(object) then
2017        local index = path[1]
2018        return object:sub(index, index)
2019    end
2020end
2021
2022---
2023-- Checks if path is a direct property.
2024-- @usage local object = {a={b={c={d}}}}
2025-- print(_.has(object, {'a', 'b', 'c'}))
2026-- --> true
2027--
2028-- @param object The object to query
2029-- @param path The path to check (Array)
2030_.has = function (object, path)
2031    local obj = object
2032    local c = 1
2033    local exist = true
2034    while not _.isNil(path[c]) do
2035        obj = obj[path[c]]
2036        if _.isNil(obj) then
2037            exist = false
2038            break
2039        end
2040        c = c + 1
2041    end
2042    return exist
2043end
2044
2045---
2046-- This method is like _.find except that it returns the key of the
2047-- first element predicate returns truthy for instead of the element itself.
2048-- @usage _.print(_.findKey({a={a = 1}, b={a = 2}, c={a = 3, x = 1}},
2049-- function(v)
2050--     return v.a == 3
2051-- end))
2052-- --> c
2053--
2054-- @param object The collection to search. (table|string)
2055-- @param predicate The function invoked per iteration
2056-- @param selfArg The self binding of predicate.
2057-- @return Returns the key of the matched element, else nil
2058_.findKey = function (object, predicate, selfArg)
2059    for k, v in _.iter(object) do
2060        if callIteratee(predicate, selfArg, v, k, object) then
2061            return k
2062        end
2063    end
2064end
2065
2066---
2067-- This method is like _.find except that it returns the key of the
2068-- first element predicate returns truthy for instead of the element itself.
2069-- @usage _.print(_.findLastKey({a={a=3}, b={a = 2}, c={a=3, x = 1}},
2070-- function(v)
2071--     return v.a == 3
2072-- end))
2073-- --> c
2074--
2075-- @param object The object to search. (table|string)
2076-- @param predicate The function invoked per iteration
2077-- @param selfArg The self binding of predicate.
2078-- @return Returns the key of the matched element, else nil
2079_.findLastKey = function (object, predicate, selfArg)
2080    for k, v in _.iterRight(object) do
2081        if callIteratee(predicate, selfArg, v, k, object) then
2082            return k
2083        end
2084    end
2085end
2086
2087---
2088-- Creates an array of function property names from all enumerable
2089-- properties, own and inherited, of object.
2090-- @usage _.print(_.functions(table))
2091-- --> {"concat", "insert", "maxn", "pack", "remove", "sort", "unpack"}
2092--
2093-- @param object The object to inspect.
2094-- @return Returns the new array of property names.
2095_.functions = function(object)
2096    local t = {}
2097    for k, v in _.iter(object) do
2098        if _.isFunction(v) then
2099            _.push(t, k)
2100        end
2101    end
2102    return t
2103end
2104
2105---
2106-- Creates an object composed of the inverted keys and values of object.
2107-- If object contains duplicate values, subsequent values overwrite
2108-- property assignments of previous values unless multiValue is true.
2109-- @usage _.print(_.invert({a='1', b='2', c='3', d='3'}))
2110-- --> {[2]="b", [3]="d", [1]="a"}
2111-- _.print(_.invert({a='1', b='2', c='3', d='3'}, true))
2112-- --> {[2]="b", [3]={"c", "d"}, [1]="a"}
2113--
2114-- @param object The object to invert.
2115-- @param multiValue Allow multiple values per key.
2116-- @return Returns the new inverted object.
2117_.invert = function (object, multiValue)
2118    local t = {}
2119    for k, v in _.iter(object) do
2120        if multiValue and not _.isNil(t[v]) then
2121            t[v] = { t[v] }
2122            _.push(t[v], k)
2123        else
2124            t[v] = k
2125        end
2126    end
2127    return t
2128
2129end
2130
2131local getSortedKeys = function(collection, desc)
2132    local sortedKeys = {}
2133    for k, v in pairs(collection) do
2134        table.insert(sortedKeys, k)
2135    end
2136    if desc then
2137        table.sort(sortedKeys, _.gt)
2138    else
2139        table.sort(sortedKeys, _.lt)
2140    end
2141    return sortedKeys
2142end
2143
2144---
2145-- Creates an array of the own enumerable property names of object.
2146-- @usage _.print(_.keys("test"))
2147-- --> {1, 2, 3, 4}
2148-- _.print(_.keys({a=1, b=2, c=3}))
2149-- --> {"c", "b", "a"}
2150--
2151-- @param object The object to query. (table|string)
2152-- @return Returns the array of property names.
2153_.keys = function (object)
2154    if _.isTable(object) then
2155        return getSortedKeys(object)
2156    elseif _.isString(object) then
2157        local keys = {}
2158        for i=1, #object do
2159            keys[i] = i
2160        end
2161        return keys
2162    end
2163end
2164
2165---
2166-- Creates a two dimensional array of the key-value pairs for object.
2167-- @usage  _.print(_.pairs({1, 2, 'x', a='b'}))
2168-- --> {{1, 1}, {2, 2}, {3, "x"}, {"a", "b"}}
2169--
2170-- @param object The object to query
2171-- @return Returns the new array of key-value pairs.
2172_.pairs = function (object)
2173    local t = {}
2174    for k, v in _.iter(object) do
2175        _.push(t, {k, v})
2176    end
2177    return t
2178end
2179
2180---
2181-- This method is like _.get except that if the resolved value is a
2182-- function it’s invoked with additional parameters and its result is returned.
2183-- @usage local object = {a=5, b={c=function(a) print(a) end}}
2184-- _.result(object, {'b', 'c'}, nil, 5)
2185-- --> 5
2186--
2187-- @param object The object to query.
2188-- @param path The path of the property to get.
2189-- @param[opt=nil] defaultValue The value returned if the resolved value is nil.
2190-- @param ... Additional parameters to pass to function
2191-- @return Returns the resolved value.
2192_.result = function (object, path, defaultValue, ...)
2193    local result = _.get(object, path, defaultValue)
2194    if _.isFunction(result) then
2195        return result(...)
2196    else
2197        return result
2198    end
2199end
2200
2201
2202---
2203-- Creates an array of the own enumerable property values of object.
2204-- @usage _.print(_.values("test"))
2205-- --> {"t", "e", "s", "t"}
2206-- _.print(_.values({a=1, b=2, c=3}))
2207-- --> {1, 3, 2}
2208--
2209-- @param object The object to query. (table|string)
2210-- @return Returns the array of property values.
2211_.values = function (object)
2212    local t = {}
2213    for k, v in _.iter(object) do
2214        _.push(t, v)
2215    end
2216    return t
2217end
2218
2219--- String
2220-- @section String
2221
2222
2223--- Utility
2224-- @section Utility
2225
2226---
2227-- Creates a function that returns value.
2228-- @usage local object = {x=5}
2229-- local getter = _.constant(object)
2230-- _.print(getter() == object);
2231-- --> true
2232--
2233-- @param value Any value.
2234-- @return Returns the new function.
2235_.constant = function(value)
2236    return _.func(value)
2237end
2238
2239---
2240-- This method returns the first argument provided to it.
2241-- @usage local object = {x=5}
2242-- _.print(_.identity(object) == object);
2243-- --> true
2244--
2245-- @param value Any value.
2246-- @return Returns value.
2247_.identity = function(...) return ... end
2248
2249local iterCollection = function(table, desc)
2250    local sortedKeys = getSortedKeys(table, desc)
2251    local i = 0
2252    return function ()
2253        if _.lt(i, #sortedKeys) then
2254            i = i + 1
2255            local key = sortedKeys[i]
2256            return key, table[key]
2257        end
2258    end
2259end
2260
2261_.iter = function(value)
2262    if _.isString(value) then
2263        local i = 0
2264        return function()
2265            if _.lt(i, #value) then
2266                i = i + 1
2267                local c = value:sub(i, i)
2268                return i, c
2269            end
2270        end
2271    elseif _.isTable(value) then
2272        return iterCollection(value)
2273    else
2274        return function() end
2275    end
2276end
2277
2278_.iterRight = function(value)
2279    if _.isString(value) then
2280        local i = #value + 1
2281        return function()
2282            if _.gt(i, 1) then
2283                i = i - 1
2284                local c = value:sub(i, i)
2285                return i, c
2286            end
2287        end
2288    elseif _.isTable(value) then
2289        return iterCollection(value, true)
2290    else
2291        return function() end
2292    end
2293end
2294
2295---
2296-- A no-operation function that returns nil regardless of the arguments
2297-- it receives.
2298-- @usage local object = {x=5}
2299-- _.print(_.noop(object) == nil);
2300-- --> true
2301--
2302-- @param ... Any arguments
2303-- @return Returns nil
2304_.noop = function(...) return nil end
2305
2306
2307---
2308-- Print more readable representation of arguments using _.str
2309-- @usage _.print({1, 2, 3, 4, {k=2, {'x', 'y'}}})
2310-- --> {1, 2, 3, 4, {{"x", "y"}, [k]=2}}
2311--
2312-- @param ... values to print
2313-- @return Return human readable string of the value
2314_.print = function(...)
2315    local t = _.table(...)
2316    for i, v in ipairs(t) do
2317        t[i] = _.str(t[i])
2318    end
2319    return print(_.args(t))
2320end
2321
2322---
2323-- Creates an array of numbers (positive and/or negative) progressing
2324-- from start up to, including, end.
2325-- If end is not specified it’s set to start with start then set to 1.
2326-- @usage _.print(_.range(5, 20, 3))
2327-- --> {5, 8, 11, 14, 17, 20}
2328--
2329-- @param[opt=1] start The start of the range.
2330-- @param stop Then end of the range.
2331-- @param[opt=1] step The value to increment or decrement by
2332-- @return Returns the new array of numbers
2333_.range = function(start, ...)
2334    local start = start
2335    local args = _.table(...)
2336    local a, b, c
2337    if #args == 0 then
2338        a = 1   -- according to lua
2339        b = start
2340        c = 1
2341    else
2342        a = start
2343        b = args[1]
2344        c = args[2] or 1
2345    end
2346    local t = {}
2347    for i = a, b, c do
2348        _.push(t, i)
2349    end
2350    return t
2351end
2352
2353return _
2354
2355