LINQ for JavaScript library, which allows to work with arrays in a more easy way and focus on business logic.
Download and link manually. Or install it
bower install mini-linq-js --save
npm install mini-linq-js --save
Just link mini-linq.js
or mini-linq.min.js
in your html.
<script type="text/javascript" src="mini-linq.min.js"></script>
You can also attach and use mini-linq with knockout observableArray. Just link mini-linq.knockout.js
.
Also you may use postponed lazy-execution for arrays by linking mini-linq.lazy.js
.
You also may use it in your Node.JS project by using
require('mini-linq-js');
- any
- all
- where
- select
- selectMany
- count
- orderBy
- orderByDescending
- groupBy
- distinct
- firstOrDefault
- lastOrDefault
- joinWith
- groupJoinWith
- contains
- aggregate
- sum
- min
- max
- skip
- take
- ofType
- union
- except
- Predicate - function which accepts arguments (value, index, array) and returns:
true
if arguments matches specified business-logic conditions;false
otherwise; - Selector - function which accepts arguments (value, index, array) and returns some value which should be used instead of original value.
- Comparator - function which accepts two arguments and returns
true
if two arguments are equal andfalse
otherwise. - Order comparator - function which accepts two arguments and returns:
1
if first argument is greater then second;-1
if second argument is greater then first;0
if they are equal.
Predicates, selectors, comparators can be written in 3 ways:
- usual way:
function(arg) { return arg * 2; }
; - modern way (by using arrow functions):
arg => arg * 2
; - modern way with obsolete browsers support:
'arg => arg * 2'
. It's almost the same as in p.2, just wrapped as a string. mini-linq core will parse this string and generated appropriate function. Important! It's not possible to use closure variables using this way.
.any
checks if there is at least one element in array which matches predicate. If called without predicate then it checks for any element in the array.
.any
accepts predicate or nothing.
true
if there is at least one element which matches specified predicate; false
otherwise.
[1, 2, 3].any(); // will return true, because predicate is not passed and array is not empty
[1, 2, 3].any(a => a > 2); // will return true because there is at least one element which match predicate a > 2
[1, 2, 3].any(a => a < 0); // will return false. There are no elements which match predicate a < 0
[].any(); // will return false. Array is empty.
.all
checks if all elements in array match predicate.
.all
accepts predicate.
true
if all elements match specified predicate; false
otherwise.
[1, 2, 3].all(a => a > 0); // will return true because all elements matches predicate a > 0
[1, 2, 3].all(a => a > 2); // will return false, because not all elements matches predicate a > 2
.where
selects all elements which match predicate.
.where
accepts predicate.
Array of elements which match predicate. Or empty array if there are no such elements.
[1, 2, 3, 4].where(a => a > 2); // will return [3, 4]
[1, 2, 3, 4].where(a => a > 5); // will return [] (empty array)
.select
produces new array by applying selector for each element.
.select
accepts selector.
Array of elements produced by applying selector. Or empty array if there are no elements.
[1, 2, 3, 4].select(s => s * 10); // will return [10, 20, 30, 40]
[].select(a => a * 10); // will return [] (empty array)
.selectMany
produces new array by applying selector for each element and combining selected arrays together into one single array.
.selectMany
accepts selector.
Array of elements produced by applying selector. Or empty array if there are no elements.
var testArray = [
{ x: [1, 2], y: 0 },
{ x: [3, 4], y: 1 },
{ x: [5, 6], y: 2 }];
testArray.selectMany(sm => sm.x); // will return [1, 2, 3, 4, 5, 6]
testArray.selectMany(sm => sm.y); // will return [] because 'y' fields are not arrays
.count
calculates count of elements which match predicate. If called without predicate then it will return total count of elements.
.count
accepts predicate or nothing.
Count of elements which match specified predicate. Or total count of elements if predicate is not specified.
[1, 2, 3, 4].count(s => c > 2); // will return 2
[1, 2, 3, 4].count(); // will return 4
.orderBy
order elements in ascending order by using selector and order comparator (if specified).
.orderBy
accepts selector as first argument and may accept order comparator as a second argument.
Array of ordered elements.
[2, 1, 4, 3].orderBy(s => s); // will return [1, 2, 3, 4]
[2, 1, 4, 3].orderBy(s => s, (first, second) => first - second); // will return [1, 2, 3, 4]
.orderByDescending
order elements in descending order by using selector and order comparator (if specified).
.orderByDescending
accepts selector as first argument and may accept order comparator as a second argument.
Array of ordered elements.
[2, 1, 4, 3].orderByDescending(s => s); // will return [4, 3, 2, 1]
[2, 1, 4, 3].orderByDescending(s => s, (first, second) => first - second); // will return [4, 3, 2, 1]
.groupBy
group elements by specified selector as a key.
.groupBy
accepts selector as first argument and may accept result selector as a second argument. If result selector is not specified then (group, values) => { group: group, values: values }
selector will be used.
Array of grouped elements.
[2, 1, 4, 3, 5, 6].groupBy(s => s % 2); // will return [{group: '0', values: [2, 4, 6]}, {group: '1', values: [1, 3, 5]}]
[2, 1, 4, 3, 5, 6].groupBy(s => s % 2, (group, values) => (group == 0 ? 'even: ' : 'odd: ') + values); // Will return ["even: 2,4,6", "odd: 1,3,5"]
.distinct
selects distinct elements by using selector as a key or element if selector is not specified, and comparator (optional) to compare equality of keys
.distinct
may accept selector as a first argument and comparator as a second argument.
Array of distinct elements.
[2, 1, 2, 3, 1, 6, 7, 3, 2].distinct(); // will return [2, 1, 3, 6, 7]
[2, 1, 2, 3, 1, 6, 7, 3, 2].distinct(d => d % 3); // will return [2, 1, 3]
[1, 2, '2', '3', 3, 4, 5, 8, 5].distinct(); // will return [1, 2, '2', '3', 3, 4, 5, 8] (default comparator is "a === b";
[1, 2, '2', '3', 3, 4, 5, 8, 5].distinct('x => x', '(a, b) => a == b'); // will return [1, 2, '3', 4, 5, 8] (here we used custom comparator)
.firstOrDefault
selects first element which matches predicate if there is not such element, then null
will be returned. If predicate is not specified then first element will be returned or null
if array is empty.
.firstOrDefault
may accept predicate.
First element which matches predicate or null
if there is no such element. If predicate is not specified then first element will be returned or null
if array is empty.
[2, 1, 2, 3, 1, 6, 7, 3, 2].firstOrDefault(f => f % 2 == 1); // will return 1
[2, 1, 2, 3, 1, 6, 7, 3, 2].firstOrDefault() // will return 2
[2, 1, 2, 3, 1, 6, 7, 3, 2].firstOrDefault(f => f < 0) // will return null
[].firstOrDefault() // will return null
.lastOrDefault
selects last element which matches predicate if there is not such element, then null
will be returned. If predicate is not specified then last element will be returned or null
if array is empty.
.lastOrDefault
may accept predicate.
Last element which matches predicate or null
if there is no such element. If predicate is not specified then last element will be returned or null
if array is empty.
[2, 1, 2, 3, 1, 6, 7, 3, 2].lastOrDefault(f => f % 2 == 1); // will return 3
[2, 1, 2, 3, 1, 6, 7, 3, 9].lastOrDefault() // will return 9
[2, 1, 2, 3, 1, 6, 7, 3, 2].lastOrDefault(f => f < 0) // will return null
[].lastOrDefault() // will return null
.joinWith
combines two arrays based upon the inner key selector and outer key selector.
.joinWith
accepts following arguments (1-4 are mandatory, 5-th is optional):
- inner array to join with;
- inner key selector which will be applied to inner array elements;
- outer key selector which will be applied to outer array elements;
- result selector which should accept two arguments (inner element and outer element) and return result element;
- key comparator which implements comparation logic between inner key and outer key. (optional)
Array of combined elements.
[1, 2, 8, 2, 6, 3, 9, 2, 4].joinWith([1, 2, 3, 4], 'ik => ik', 'ok => ok', '(i, o) => i'); // will return [1, 2, 2, 3, 2, 4]
[1, 2, 3].joinWith([4, 5, 6], ik => true, ok => true, (i, o) => '' + i + o); // will return ["41", "51", "61", "42", "52", "62", "43", "53", "63"]
[1, 2, 3].joinWith([1, 2, 3], ik => ik + 1, ok => ok, (i, o) => i); // will return [1, 2]
[1, 2, 3].joinWith([4, 5, 6], ik => ik, ok => ok, (i, o) => i) // will return []
.groupJoinWith
correlates the elements of two arrays based on equality of keys and groups the results.
.groupJoinWith
accepts following arguments (1-4 are mandatory, 5-th is optional):
- inner array to join with;
- inner key selector which will be applied to inner array elements;
- outer key selector which will be applied to outer array elements;
- result selector which should accept two arguments (array of matched inner element and outer element) and return result element;
- key comparator which implements comparation logic between inner key and outer key. (optional)
Array of combined elements.
[1, 2, 3, 4].groupJoinWith([1, 2, 3, 1, 2, 3], 'ik => ik', 'ok => ok', '(g, o) => g'); // will return [[1, 1], [2, 2], [3, 3], []]
[1, 2, 3, 4].groupJoinWith([], 'ik => ik', 'ok => ok', '(g, o) => o'); // will return [1, 2, 3, 4]
[].groupJoinWith([1, 2, 3, 1, 2, 3], 'ik => ik', 'ok => ok', '(g, o) => g'); // will return []
.contains
checks if passed value presents in array.
.contains
accepts value and may accept comparator as a second argument. If comparator is not passed then (a, b) => a === b
comparator will be used by default.
true
if value presents in array; false
otherwise.
[1, 2, 3, 4].contains(3); // will return true
[1, 2, 3, 4].contains(5); // will return false
[1, 2, 3, 4].contains('2'); // will return false, comparator is not passed, so === equality has been used.
[1, 2, 3, 4].contains('2', (a, b) => a == b); // will return true
.aggregate
applies an accumulator function over a sequence. It acts the same as Array.prototype.reduce
.
.aggregate
accepts accumulator function, which should accept two arguments: previous result and current element. Also may accept initial value as a second argument.
Aggregated result.
[1, 2, 3, 4].aggregate((c, n) => c + n); // will return 10
[1, 2, 3, 4].aggregate((c, n) => c + n, 10); // will return 20 (because initial value is passed)
[].aggregate((c, n) => c + n); // will return undefined
[].aggregate((c, n) => c + n, 0); // will return 0
.sum
calculates total sum of elements using selector if specified.
.sum
may accept selector.
Total sum.
[1, 2, 3, 4].sum(); // will return 10
[1, 2, 3, 4].sum(s => s); // will return 10
[1, 2, 3, 4].sum(s => s * 10); // will return 100
.min
finds minimum value using selector if specified.
.min
may accept selector.
Minimum value. Or undefined
if array is empty.
"the quick brown fox jumps over the lazy dog".split(' ').min('s => s.length'); // will return 3
[].min(); // will return undefined
[9, 5, 1, 9, 3, 5, 6].min(); // will return 1
.max
finds maximum value using selector if specified.
.max
may accept selector.
Maximum value. Or undefined
if array is empty.
"the quick brown fox jumps over the lazy dog".split(' ').max('s => s.length'); // will return 5
[].max(); // will return undefined
[9, 5, 1, 9, 3, 5, 6].max(); // will return 9
.skip
skips specified amount of elements.
.skip
accepts number of elements to skip.
Array of elements after skipped elements.
[1, 2, 3, 4].skip(2); // will return [3, 4]
[1, 2, 3, 4].skip(0); // will return [1, 2, 3, 4]
[1, 2, 3, 4].skip(9); // will return []
.take
takes specified amount of elements.
.take
accepts number of elements to take.
Array of taken elements.
[1, 2, 3, 4].take(2); // will return [1, 2]
[1, 2, 3, 4].take(0); // will return []
[1, 2, 3, 4].take(9); // will return [1, 2, 3, 4]
.ofType
filter elements based on specified type. Basically it's a shortcut for .where(w => typeof(w) === specifiedType)
.
.ofType
accepts the type to filter the elements on.
Array of elements of specified type.
[1, '2', '3', 4].ofType('string'); // will return ['2', '3']
[1, '2', '3', 4].ofType('number'); // will return [1, 4]
[1, '2', '3', 4].ofType('object'); // will return [];
.union
produces the set union of arrays by using the comparator (optional) to compare values.
.union
accepts array to combine and may accept comparator as a second argument.
Array of merged elements from source arrays.
[1, 2, 3, 4].union([2, 3, 4, 5]); // will return [1, 2, 3, 4, 5]
[1, 2, 3, 4].union([]); // will return [1, 2, 3, 4]
[].union([]); // will return []
[1, 2, 3, 4].union([2, '3', '4', 5], '(a, b) => a == b'); // will return [1, 2, 3, 4, 5];
.except
produces the set difference of two arrays by using the comparator (optional) to compare values.
.except
accepts array to compare and may accept comparator as a second argument.
Array of differences of source arrays.
[1, 2, 3, 4].except([3, 4, 5]); // will return [1, 2]
[1, 2, 3, 4].except([5, 6, 7]); // will return [1, 2, 3, 4]
[1, 2, 3, 4].except([1, 2, 3, 4]); // will return []
[1, 2, 3, 4].except(['3', 4, '5'], '(a, b) => a == b'); // will return [1, 2]
By default all mini-linq methods will execute their logic instantly and return result. But in some cases it may be useful to postpone execution, until some conditions take place.
To do this with mini-linq it's necesasry to load mini-linq.lazy.js
module. After that it will be possible to use .toLazy()
to cast array to lazy array. .toLazy()
doesn't accept any argument and returns LazyArray
instance. LazyArray
has the same mini-linq methods as normal array with the exception that some of them are not executing instantly. To get final result array you have to use .toArray()
method. For example:
[1, 2, 3, 4].toLazy(); // will return LazyArray instance
[1, 2, 3, 4].toLazy().where(w => w > 2); // will return LazyArray instance, .where is postponed, nothing executed.
[1, 2, 3, 4].toLazy().where(w => w > 2).toArray(); // will return [3, 4]
LazyArray has some optimization logic, to reduce amount of array traversals, for example:
[1, 2, 3, 4].toLazy().where(w => w > 1).where(w => w < 4).toArray(); // will merge two .where methods into one, then execute and return [2, 3] (with just one traversal)