Skip to content

LINQ for JavaScript library, which allows to work with arrays in a more easy way and focus on business logic.

License

Notifications You must be signed in to change notification settings

akopachov/mini-linq-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mini-linq.js

Description

LINQ for JavaScript library, which allows to work with arrays in a more easy way and focus on business logic.

Installation

Download and link manually. Or install it

bower install mini-linq-js --save
npm install mini-linq-js --save

Usage

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');

Available methods

Terms

  • 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 and false 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:

  1. usual way: function(arg) { return arg * 2; };
  2. modern way (by using arrow functions): arg => arg * 2;
  3. 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.

Methods description

Description:

.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.

Arguments:

.any accepts predicate or nothing.

Returns:

true if there is at least one element which matches specified predicate; false otherwise.

Example of usage:
[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.

Description:

.all checks if all elements in array match predicate.

Arguments:

.all accepts predicate.

Returns:

true if all elements match specified predicate; false otherwise.

Example of usage:
[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

Description:

.where selects all elements which match predicate.

Arguments:

.where accepts predicate.

Returns:

Array of elements which match predicate. Or empty array if there are no such elements.

Example of usage:
[1, 2, 3, 4].where(a => a > 2); // will return [3, 4]
[1, 2, 3, 4].where(a => a > 5); // will return [] (empty array)

Description:

.select produces new array by applying selector for each element.

Arguments:

.select accepts selector.

Returns:

Array of elements produced by applying selector. Or empty array if there are no elements.

Example of usage:
[1, 2, 3, 4].select(s => s * 10); // will return [10, 20, 30, 40]
[].select(a => a * 10); // will return [] (empty array)

Description:

.selectMany produces new array by applying selector for each element and combining selected arrays together into one single array.

Arguments:

.selectMany accepts selector.

Returns:

Array of elements produced by applying selector. Or empty array if there are no elements.

Example of usage:
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

Description:

.count calculates count of elements which match predicate. If called without predicate then it will return total count of elements.

Arguments:

.count accepts predicate or nothing.

Returns:

Count of elements which match specified predicate. Or total count of elements if predicate is not specified.

Example of usage:
[1, 2, 3, 4].count(s => c > 2); // will return 2
[1, 2, 3, 4].count(); // will return 4

Description:

.orderBy order elements in ascending order by using selector and order comparator (if specified).

Arguments:

.orderBy accepts selector as first argument and may accept order comparator as a second argument.

Returns:

Array of ordered elements.

Example of usage:
[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]

Description:

.orderByDescending order elements in descending order by using selector and order comparator (if specified).

Arguments:

.orderByDescending accepts selector as first argument and may accept order comparator as a second argument.

Returns:

Array of ordered elements.

Example of usage:
[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]

Description:

.groupBy group elements by specified selector as a key.

Arguments:

.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.

Returns:

Array of grouped elements.

Example of usage:
[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"]

Description:

.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

Arguments:

.distinct may accept selector as a first argument and comparator as a second argument.

Returns:

Array of distinct elements.

Example of usage:
[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)

Description:

.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.

Arguments:

.firstOrDefault may accept predicate.

Returns:

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.

Example of usage:
[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

Description:

.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.

Arguments:

.lastOrDefault may accept predicate.

Returns:

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.

Example of usage:
[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

Description:

.joinWith combines two arrays based upon the inner key selector and outer key selector.

Arguments:

.joinWith accepts following arguments (1-4 are mandatory, 5-th is optional):

  1. inner array to join with;
  2. inner key selector which will be applied to inner array elements;
  3. outer key selector which will be applied to outer array elements;
  4. result selector which should accept two arguments (inner element and outer element) and return result element;
  5. key comparator which implements comparation logic between inner key and outer key. (optional)
Returns:

Array of combined elements.

Example of usage:
[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 []

Description:

.groupJoinWith correlates the elements of two arrays based on equality of keys and groups the results.

Arguments:

.groupJoinWith accepts following arguments (1-4 are mandatory, 5-th is optional):

  1. inner array to join with;
  2. inner key selector which will be applied to inner array elements;
  3. outer key selector which will be applied to outer array elements;
  4. result selector which should accept two arguments (array of matched inner element and outer element) and return result element;
  5. key comparator which implements comparation logic between inner key and outer key. (optional)
Returns:

Array of combined elements.

Example of usage:
[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 []

Description:

.contains checks if passed value presents in array.

Arguments:

.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.

Returns:

true if value presents in array; false otherwise.

Example of usage:
[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

Description:

.aggregate applies an accumulator function over a sequence. It acts the same as Array.prototype.reduce.

Arguments:

.aggregate accepts accumulator function, which should accept two arguments: previous result and current element. Also may accept initial value as a second argument.

Returns:

Aggregated result.

Example of usage:
[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

Description:

.sum calculates total sum of elements using selector if specified.

Arguments:

.sum may accept selector.

Returns:

Total sum.

Example of usage:
[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

Description:

.min finds minimum value using selector if specified.

Arguments:

.min may accept selector.

Returns:

Minimum value. Or undefined if array is empty.

Example of usage:
"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

Description:

.max finds maximum value using selector if specified.

Arguments:

.max may accept selector.

Returns:

Maximum value. Or undefined if array is empty.

Example of usage:
"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

Description:

.skip skips specified amount of elements.

Arguments:

.skip accepts number of elements to skip.

Returns:

Array of elements after skipped elements.

Example of usage:
[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 []

Description:

.take takes specified amount of elements.

Arguments:

.take accepts number of elements to take.

Returns:

Array of taken elements.

Example of usage:
[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]

Description:

.ofType filter elements based on specified type. Basically it's a shortcut for .where(w => typeof(w) === specifiedType).

Arguments:

.ofType accepts the type to filter the elements on.

Returns:

Array of elements of specified type.

Example of usage:
[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 [];

Description:

.union produces the set union of arrays by using the comparator (optional) to compare values.

Arguments:

.union accepts array to combine and may accept comparator as a second argument.

Returns:

Array of merged elements from source arrays.

Example of usage:
[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];

Description:

.except produces the set difference of two arrays by using the comparator (optional) to compare values.

Arguments:

.except accepts array to compare and may accept comparator as a second argument.

Returns:

Array of differences of source arrays.

Example of usage:
[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)

Author

Alexander Kopachov ([email protected])

License

MIT

About

LINQ for JavaScript library, which allows to work with arrays in a more easy way and focus on business logic.

Resources

License

Stars

Watchers

Forks

Packages

No packages published