Package Exports
- fromjs
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (fromjs) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
from.js
from.js is a super fast, extremely-optimized LINQ engine for JavaScript.
Features
- High-performance
- Supports most LINQ functions that .NET provides
- 100% lazy evaluation
- Supports lambda expression
Supported platforms
- Web
- node.js
Concept
from.js is intended to make it easy to use LINQ in JavaScript for whom is familiar with .NET environment. Most functions are adopted from .NET, and some features are modified/added to utilize characteristics of JavaScript.
Importing module
Web
<script src='from.js'></script>
node.js (It can be installed by using npm install fromjs)
var from = require('fromjs');
Basic iteration
You can basically iterate Array, String, Object by using each().
var array = [1, 2, 3, 4];
from(array).each(function (value, key) {
console.log('Value ' + value + ' at index ' + key);
});
// Value 1 at index 0
// Value 2 at index 1
// Value 3 at index 2
// Value 4 at index 3
var o = {foo: 1, bar: 2};
from(o).each(function (value, key) {
console.log(key + ' = ' + value);
});
// foo = 1
// bar = 2
An iteration can be stopped by returning false.
var array = [1, 2, 3, 4];
from(array).each(function (value, key) {
console.log('Value ' + value + ' at index ' + key);
return value != 2;
});
// Value 1 at index 0
// Value 2 at index 1
broken parameter can be used to investigate either the iteration was broken.
var array = [1, 2, 3, 4];
var broken = from(array).each(function (value, key) {
return value != 2;
}).broken;
console.log(broken); // true
Basic query
Printing numbers less than 5 in an array
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
from(numbers)
.where(function (value) {
return value < 5;
})
.each(function (value) {
console.log(value);
});
Printing each number + 1 in an array
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
from(numbers)
.select(function (value) {
return value + 1;
})
.each(function (value) {
console.log(value);
});
Printing the average of top 3 grades
var grades = [ 59, 82, 70, 56, 92, 98, 85 ];
var average = from(grades)
.orderByDesc()
.take(3)
.average();
console.log(average);
Lambda expression
It will be so tiring work to write every nested function every time. It can be evaded by using lambda expression. Its format is almost same as C#'s.
Here's an example.
function (arg1, arg2, arg3) {
return arg1 * arg2 + arg3;
}
The function given above can be re-written as below using lambda expression.
(arg1, arg2, arg3) => arg1 * arg2 + arg3
Parentheses can be omitted when it has only one argument.
arg1 => arg1 * 3
Now let's apply it into real JavaScript code.
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
from(numbers)
.where(function (value) {
return value < 5;
})
.each(function (value) {
console.log(value);
});
The example above can be re-written as below.
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
from(numbers)
.where('value => value < 5')
.each('value => console.log(value)');
Omitting argument list
Lambda expression can be shorten more by omitting argument list. But how can it be used without any argument specified? from.js provides several abbreviations which can be used in this case.
Abbreviation | Meaning |
---|---|
#n | The n-th argument (zero based) |
$ | The first argument (same as #0) |
$$ | The second argument (same as #1) |
@ | The last argument |
For example,
(arg0, arg1, arg2, arg3) => arg0 * arg1 + arg2 * arg3
the expression above can be shorten as below.
#0 * #1 + #2 * #3
or
$ * $$ + #2 * @
Let's apply it into JavaScript code.
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
from(numbers)
.where(function (value) {
return value < 5;
})
.each(function (value) {
console.log(value);
});
The sample above can be shorten as below.
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
from(numbers).where('$ < 5').each('console.log($)');
As you will see, most predicator functions have similar arguments list (except comparers). In most cases, the first argument means 'value', the second means 'key', and the last means 'external argument'. (This is the most different part from .NET) You can habitually consider $ as a value, $$ as a key, and @ as an external argument.
External argument
Because lambda expressions are given as String, any variables in the current context can't be referenced. For example,
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
var n = 5;
from(numbers).where('value => value < n').each('value => console.log(value)');
this code won't work. Then how can it be get around? Most predicator functions provided by from.js support external argument. If an object is given as an external argument, it can be referenced in lambda expression.
The example above should be like this:
var numbers = [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ];
var n = 5;
from(numbers).where('(value, key, arg) => value < arg', n).each('value => console.log(value)');
// or simply
from(numbers).where('$ < @', n).each('console.log($)');
Some more conveniences on lambda expression
There are still more chances to shorten lambda expressions.
- 'Dot' can be omitted between $,$$,@ and following keyword. For instance, $length will be processed identically as $.length.
// Print fruit names ordered by its length
var fruits = [ "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" ];
from(fruits).orderBy('$length').each('console.log($)');
- Referencing array of $,$$,@ can be shorten like this: @[3] --> @3
var fruits = [ "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" ];
var appleOrBanana = from(fruits).count('$ == @0 || $ == @1', ['apple', 'banana']);
console.log(appleOrBanana); // 2
Empty iterable
Sometimes it is needed to use an empty iterable object. In this case, simply call from() without any argument,
var names1 = [ "Hartono, Tommy" ];
var names2 = [ "Adams, Terry", "Andersen, Henriette Thaulow", "Hedlund, Magnus", "Ito, Shu" ];
var names3 = [ "Solanki, Ajay", "Hoeing, Helge", "Andersen, Henriette Thaulow", "Potra, Cristina", "Iallo, Lucio" ];
var namesList = [ names1, names2, names3 ];
// Only include arrays that have four or more elements
from(namesList)
.aggregate(from(), "(current, next) => next.length > 3 ? current.union(next) : current")
.each("console.log($)");
/*
This code produces the following output:
Adams, Terry
Andersen, Henriette Thaulow
Hedlund, Magnus
Ito, Shu
Solanki, Ajay
Hoeing, Helge
Potra, Cristina
Iallo, Lucio
*/
Ranged iterable
It is able to generate a ranged iterable by using from.range().
from.range(n) // from 0 to n - 1
from.range(start, end) // from start to end - 1
from.range(start, end, step) // from start to end - 1, increasing by step
from.range(4)
.select("$ * $")
.each("console.log($)");
/*
This code produces the following output:
0
1
4
9
*/
// Generate a sequence of three integers starting at 4,
// and then select their squares.
from.range(4, 7)
.select("$ * $")
.each("console.log($)");
/*
This code produces the following output:
16
25
36
*/
from.range(3, 13, 3)
.select("$ * $")
.each("console.log($)");
/*
This code produces the following output:
9
36
81
144
*/
Supported queries
- [aggregate](https://github.com/suckgamoni/fromjs/wiki/aggregate(seed, func[, arg]%29)
- [all](https://github.com/suckgamoni/fromjs/wiki/all(predicate[, arg]%29)
- [any](https://github.com/suckgamoni/fromjs/wiki/any([predicate, arg]%29)
- at
- [atOrDefault](https://github.com/suckgamoni/fromjs/wiki/atOrDefault(index, defValue%29)
- average
- concat
- [contains](https://github.com/suckgamoni/fromjs/wiki/contains(value[, comparer, arg]%29)
- [count](https://github.com/suckgamoni/fromjs/wiki/count([predicate, arg]%29)
- defaultIfEmpty
- [distinct](https://github.com/suckgamoni/fromjs/wiki/distinct([comparer, arg]%29)
- [except](https://github.com/suckgamoni/fromjs/wiki/except(second[, comparer, arg]%29)
- [first](https://github.com/suckgamoni/fromjs/wiki/first([predicate, arg]%29)
- [firstOrDefault](https://github.com/suckgamoni/fromjs/wiki/firstOrDefault(defValue%29 , firstOrDefault(predicate, defValue[, arg]%29)
- [groupBy](https://github.com/suckgamoni/fromjs/wiki/groupBy(selectors[, comparer, arg]%29)
- [groupJoin](https://github.com/suckgamoni/fromjs/wiki/groupJoin(inner, outerKeySelector, innerKeySelector, resultSelector[, comparer, arg]%29)
- [intersect](https://github.com/suckgamoni/fromjs/wiki/intersect(second[, comparer, arg]%29)
- [join](https://github.com/suckgamoni/fromjs/wiki/join(inner, outerKeySelector, innerKeySelector, resultSelector[, comparer, arg]%29)
- [last](https://github.com/suckgamoni/fromjs/wiki/last([predicate, arg]%29)
- [lastOrDefault](https://github.com/suckgamoni/fromjs/wiki/lastOrDefault(defValue%29 , lastOrDefault(predicate, defValue[, arg]%29)
- [max](https://github.com/suckgamoni/fromjs/wiki/max([selector, arg]%29)
- [min](https://github.com/suckgamoni/fromjs/wiki/min([selector, arg]%29)
- [orderBy](https://github.com/suckgamoni/fromjs/wiki/orderBy(keySelector[, comparer, arg]%29)
- [orderByDesc](https://github.com/suckgamoni/fromjs/wiki/orderByDesc(keySelector[, comparer, arg]%29)
- reverse
- [select](https://github.com/suckgamoni/fromjs/wiki/select(selector[, arg]%29)
- [selectMany](https://github.com/suckgamoni/fromjs/wiki/selectMany(selector[, arg]%29)
- [selectPair](https://github.com/suckgamoni/fromjs/wiki/selectPair(valueSelector, keySelector[, arg]%29)
- [sequenceEqual](https://github.com/suckgamoni/fromjs/wiki/sequenceEqual(second[, comparer, arg]%29)
- [single](https://github.com/suckgamoni/fromjs/wiki/single([predicate, arg]%29)
- [singleOrDefault](https://github.com/suckgamoni/fromjs/wiki/singleOrDefault(defValue%29 , singleOrDefault(predicate, defValue[, arg]%29)
- skip
- [skipWhile](https://github.com/suckgamoni/fromjs/wiki/skipWhile(predicate[, arg]%29)
- sum
- take
- [takeWhile](https://github.com/suckgamoni/fromjs/wiki/takeWhile(predicate[, arg]%29)
- [thenBy](https://github.com/suckgamoni/fromjs/wiki/thenBy(keySelector[, comparer, arg]%29)
- [thenByDesc](https://github.com/suckgamoni/fromjs/wiki/thenByDesc(keySelector[, comparer, arg]%29)
- toArray
- toJSON
- toString
- toURLEncoded
- [trim](https://github.com/suckgamoni/fromjs/wiki/trim([left, right, arg]%29)
- [union](https://github.com/suckgamoni/fromjs/wiki/union(second[, comparer, arg]%29)
- [where](https://github.com/suckgamoni/fromjs/wiki/where(predicate[, arg]%29)
- [zip](https://github.com/suckgamoni/fromjs/wiki/zip(second, resultSelector[, arg]%29)
Some practical examples
// Determine either n is a prime number.
function isPrime(n) {
return n == 2 ||
(n % 2 == 1 &&
!from.range(3, n, 2)
.takeWhile('$ * $ <= @', n)
.any('@ % $ == 0', n));
}
// Get prime numbers bigger than n.
// Returns [count] numbers in a array, or a single number if count is zero.
function getPrimeBiggerThan(n, count) {
n = parseInt(n) + 1;
if (n % 2 == 0) ++n;
var query = from.range(n, Infinity, 2).where('@($)', isPrime);
if (!count) {
return query.first();
} else {
return query.take(count).toArray();
}
}
console.log(getPrimeBiggerThan(10, 5));
// [ 11, 13, 17, 19, 23 ]
function splitTrimmed(s, delimiter) {
return from(s.split(delimiter))
.select('from($).trim().toString()')
.where('$length > 0')
.toArray();
}
var s = splitTrimmed(' a | b | c | | d | | ', '|');
console.log(s);
// [ 'a', 'b', 'c', 'd' ]
var array = [1, 2, 3];
// Make a shallow copy of a array
var copy = from(array).toArray();
array.push(4);
console.log(copy);
// [ 1, 2, 3 ]