Fluent, Linq-Style Query Expressions for Lua
With LuaRocks:
LuaRocks install LunaQuery
Otherwise, just copy LunaQuery.lua to your project directory or lua path.
Enumerable = require 'LunaQuery'
Many methods take one or more functions as parameters. For convenience, these can be written as lambda expression strings, with comma-separated parameter names and a thin arrow, followed by the expression to return.
The following are equivalent:
local function negativize (n)
return -n
end
--Using External Functions
local e = Enumerable{1,2,3,4}
:skip(2)
:select(negativize) --local externally-declared function
:forEach(print) --global function
--Using Inline Functions
local e = Enumerable{1,2,3,4}
:skip(2)
:select(function(a) return -a end) --anonymous function
:forEach(function(a) return print(a) end) --anonymous function
--Using Lambda Expressions
local e = Enumerable{1,2,3,4}
:skip(2)
:select('(a) -> -a') -- inline string
:forEach('(a) -> print(a)') -- inline string
-3
-4
Note: all functions parsed from lambda strings will be scoped globally-- If your function needs to access local variables, don't specify it as a string.
local function negativize (n)
return -n
end
--Don't Do This
local e = Enumerable{1,2,3,4}
:skip(2)
:select('(a) -> negativize(a)') -- ERROR: lambda strings can't reference locals!
:forEach('(a) -> print(a)') -- print() is global, so this is OK
🌘 All Methods take self as the initial parameter.
aggregate all any append average concat contains count defaultIfEmpty distinct elementAt elementAtOrDefault empty except first firstOrDefault forEach fromDictionary fromHashSet fromList |
groupBy groupJoin intersect join last lastOrDefault max min ofType orderBy orderByDescending prepend range repeatElement reverse select selectMany sequenceEqual single singleOrDefault |
skip skipLast skipWhile sum take takeLast takeWhile thenBy thenByDescending toArray toDictionary toEnumerable toHashSet toList toLookup union where zip |
---|
Applies an accumulator function over each element, beginning with an initial value
accumulator
is a function which takes two parameters.initialValue
must be the same as the return type
Examples:
numberString = Enumerable{1,2,3}:aggregate('(a,b) -> a .. tostring(b)', '')
print(numberString)
123
Returns true if the predicate is true for every element
predicate
is a function with a single parameter.
Examples:
allOddNumbers = Enumerable{1,3,4,5}:all('(n) -> n % 2 == 1')
print(allOddNumbers)
false
Returns true if the predicate is true for at least one element
predicate
is a function with a single parameter. The default predicate always returns true.
Examples:
emptySetHasMembers = Enumerable{}:any()
print(emptySetHasMembers)
false
nonemptySetHasMembers = Enumerable{'zxcvbn'}:any()
print(nonemptySetHasMembers)
true
anyOddNumbers = Enumerable{1,3,4,5}:any('(n) -> n % 2 == 1')
print(anyOddNumbers)
true
Adds a single element to the end of the sequence
Examples:
oneMore = Enumerable{'una', 'vez'}
:append('mas')
:forEach(print)
una
vez
mas
Sum of the sequence divided by the count
selector
is a single-parameter function of each element. The default selector returns each element unchanged.
Examples:
averageNumbers = Enumerable{1,2,3,4}:average()
print(averageNumbers)
2.5
averageNameLength = Enumerable{'thomas', 'richard', 'harold'}:average('(a) -> #a')
print(averageNameLength)
6.3333333333333
Concatenates another sequence onto the end of this one
second
is anotherEnumerable
Examples:
Enumerable{'lettuce', 'meat', 'tomato'}
:concat(Enumerable{'onion', 'pickles'})
:forEach(print)
lettuce
meat
tomato
onion
pickles
Returns true if one or more elements is equal to the provided value
equalComparer
is a two-parameter function returning true or false.
Examples:
hasWheat = Enumerable{'rice', 'beans', 'squash'}:contains('wheat')
print(hasWheat)
false
inventory = Enumerable{
{
id = 80153,
type = 'book',
title = 'The Hobbit'
},
{
id = 94532,
type = 'book',
title = 'Snow Crash'
}
}
desiredBook = {
type = 'book',
title = 'The Hobbit'
}
inStock = inventory:contains(desiredBook, '(a,b) -> a.title == b.title')
print(inStock)
true
How many elements are in the sequence, or how many satisfy the predicate if one is provided.
predicate
is a function with a single parameter. The default predicate always returns true.
Examples:
fowlCount = Enumerable{'duck', 'duck', 'duck', 'duck', 'goose'}
:count()
print(fowlCount)
5
ducksOnly = Enumerable{'duck', 'duck', 'duck', 'duck', 'goose'}
:count('(bird) -> bird == "duck"')
print(ducksOnly)
4