Skip to content

LINQ to JS port using ESnext iterators and generators.

License

Notifications You must be signed in to change notification settings

mcibique/linq-for-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

linq-for-js npm version

LINQ to JS port using ESnext iteration protocol and generators.

Performance

Just like in LINQ, the iterable chain is not performing any operation until the iteration is executed, which allows you to build up the chain:

let query = customers.where(customer => customer.age > 18).select(customer => customer.id); // this only returns the iterator, no operation has been performed so far
let filtered = query.toArray(); // or Array.from(query), or for (let id of query) { ... }

The query is being iterated in most performant way: select() command is executed only on customers filtered by where() command. If you have 100 customers and 10 are over 18, where() command executes 100 times, select() only 10.

Lets try to get only first customer which is over 18:

let query = customers.where(customer => customer.age > 18).select(customer => customer.id) // again, this only returns the iterator, no operation has been performed so far
let customerId = query.first(); // get me the first customer ID which matches the query;

Here, the where() command executes until it finds first customer with age over 18. Then the select() command is performed only with filtered customer and the result is returned.

LINQ is not only about select() and where(), it contains a set of chainable methods which allows you to build up a query and then execute it. Check out how they fit together in Chaining examples.

Installing

npm install linq-for-js --save --save-exact

Using directly in browser

Linq-for-js requires babel-polyfill to run in browser. The polyfill is not included in the bundle and must be added before the linq-for-js.min.js.

npm install babel-polyfill --save --save-exact
<script src="/node_modules/babel-polyfill/dist/polyfill.min.js"></script>
<script src="/node_modules/linq-for-js/dist/linq-for-js.min.js"></script>

Methods implemented

Usage

Where

let array = [1, 2, 3, 4, 5];
for (let item of array.where(item => item > 3)) {
  console.log(item);
}

// 4
// 5

or

let array = [1, 2, 3, 4, 5];
let filtered = Array.from(array.where(item => item > 3));
// [4, 5]

or

let array = [1, 2, 3, 4, 5];
let filtered = array.where(item => item > 3).toArray();
// [4, 5]

or

let array = [1, 2, 3, 4, 5];
let filtered = [...array.where(item => item > 3)];
// [4, 5]

or

let array = [
  { id: 1, title: 'Title 1', price: 20 },
  { id: 2, title: 'Title 2', price: 35 },
  { id: 3, title: 'Title 3', price: 15 }
];
let map = array.where(product => product.price < 30).toMap(product => product.id, product => product.title);
// [[1, 'Title 1'], [3, 'Title 3']]
map instanceof Map;
// true

or

let customers = [
  { name: 'John', age: 15 },
  { name: 'Joe', age: 19 },
  { name: 'Anna', age: 21 }
];

let filtered = customers
  .where(customer => customer.age > 18)
  .where(customer => customer.name.startsWith('J'))
  .toArray();
// [{ name: 'Joe', age: 19 }]

First

let array = [1, 2, 3, 4, 5];
let first = array.first();
// 1

or

let array = [1, 2, 3, 4, 5];
let first = array.first(item => item > 3);
// 4

Count

let array = [1, 2, 3, 4, 5];
let count = array.count();
// 5

or

let array = [1, 2, 3, 4, 5];
let count = array.count(item => item > 3);
// 2

Any

let array = [1, 2, 3, 4, 5];
let any = array.any();
// true

or

let array = [1, 2, 3, 4, 5];
let any = array.any(item => item < 3);
// true

or

let array = [1, 2, 3, 4, 5];
let any = array.any(item => item === 6);
// false

All

let array = [1, 2, 3, 4, 5];
let all = array.all(item => item < 3);
// false

or

let array = [1, 2, 3, 4, 5];
let all = array.all(item => item < 6);
// true

Aggregate

let array = [1, 2, 3, 4, 5];
let aggregate = array.aggregate((prev, curr) => prev + curr);
// 15

or

let customers = [
  { name: 'John', age: 15 },
  { name: 'Joe', age: 19 },
  { name: 'Anna', age: 21 }
];

let aggregate = customers.aggregate((prev, curr) => (prev.name || prev) + ', ' + curr.name);
// "John, Joe, Anna"

Sum

let array = [1, 2, 3, 4, 5];
let count = array.sum();
// 15

Take

let array = [1, 2, 3, 4, 5];
let result = array.take(3);
// [1, 2, 3]

TakeWhile

let array = [1, 2, 3, 4, 5];
let result = array.takeWhile(i => i < 3);
// [1, 2]
let array = [1, 2, 3, 4, 5];
let result = array.takeWhile(i => i < 0);
// []

Select

let array = [1, 2, 3, 4, 5];
let result = array.select(i => i ** 2).toArray();
// [1, 4, 9, 16, 25]

SelectMany

let books = [
  { title: 'Title 1', tags: ['novel', 'sci-fi'] },
  { title: 'Title 2', tags: ['drama', 'history'] }
];
let result = array.selectMany(book => book.tags).toArray();
// ['novel', 'sci-fi', 'drama', 'history']

Skip

let array = [1, 2, 3, 4, 5];
let result = array.skip(3).toArray();
// [4, 5]

Max

let array = [1, 3, 2, 5, 4];
let result = array.max();
// 5

Min

let array = [5, 2, 3, 1, 4];
let result = array.min();
// 1

Contains

let array = [1, 2, 3, 4, 5];
let result = array.contains(3);
// true

Distinct

let array = [1, 2, 3, 1, 2, 3, 4];
let result = array.distinct().toArray();
// [1, 2, 3, 4]

ElementAt

let books = [
  { title: 'Title 1', tags: ['novel', 'sci-fi'] },
  { title: 'Title 2', tags: ['drama', 'history'] }
];
let result = array.selectMany(book => book.tags).elementAt(2);
// 'drama'

Single

let array = [1, 2, 3, 4, 5];
let single = array.single(i => i % 3 === 0);
// 3

or

let array = [1, 2, 3, 4, 5];
let single = array.single(i => i % 2 === 0);
// Error: More than one element found.

Average

let array = [1, 2, 3, 4, 5];
let average = array.average();
// 3

Chaining

// where + first
let array = [1, 2, 3, 4, 5];
let first = array.where(item => item > 2).first();
// 3
// where + count
let array = [1, 2, 3, 4, 5];
let count = array.where(item => item > 3).count();
// 2
// where + average
let array = [1, 2, 3, 4, 5];
let average = array.where(item => item > 3).average();
// 4.5
// where + any
let array = [1, 2, 3, 4, 5];
let any = array.where(item => item > 3).any();
// true
// where + all
let array = [1, 2, 3, 4, 5];
let all = array.where(item => item > 3).all(item => item < 6);
// true
// where + any
let array = [1, 2, 3, 4, 5];
let any = array.where(item => item > 2).contains(4);
// true
// where + sum
let array = [1, 2, 3, 4, 5];
let count = array.where(item => item > 3).sum();
// 9
// where + max
let array = [1, 2, 3, 4, 5];
let max = array.where(item => item < 4).max();
// 3
// where + min
let array = [1, 2, 3, 4, 5];
let max = array.where(item => item > 2).min();
// 2
// where + take
let array = [1, 2, 3, 4, 5];
let count = array.where(item => item > 1).take(2);
// [2, 3]
// where + distinct
let array = [1, 2, 4, 7, 9, 10, 11, 16];
let count = array.where(item => item % 2 === 0).distinct().toArray();
// [2, 4, 10, 16]
// where + elementAt
let array = [1, 2, 3, 4, 5];
let first = array.where(item => item > 2).elementAt(1);
// 4
// select + first
let array = [1, 2, 3, 4, 5];
let first = array.select(item => item * 2).first();
// 2
// select + any
let array = [1, 2, 3, 4, 5];
let any = array.select(item => item * 3).any(item => item > 10);
// true
// select + all
let array = [1, 2, 3, 4, 5];
let all = array.select(item => item ** 2).all(item => item < 30);
// true
// select + any
let array = [1, 2, 3, 4, 5];
let any = array.select(item => item * 3).contains(12);
// true
// select + sum
let array = [1, 2, 3, 4, 5];
let sum = array.select(item => item * 2).sum();
// 30
// select + take
let array = [1, 2, 3, 4, 5];
let sum = array.take(3).select(item => item * 2).toArray();
// [2, 4, 6]
// select + takeWhile
let array = [1, 2, 3, 4, 5];
let sum = array.select(item => item * 2).takeWhile(i => i < 7).toArray();
// [2, 4, 6]
// select + skip
let array = [1, 2, 3, 4, 5];
let result = array.skip(2).select(item => item ** 2).toArray();
// [9, 16, 25]
// select + elementAt
let array = [1, 2, 3, 4, 5];
let sum = array.select(item => item * 2).elementAt(4);
// 10
// select + distinct
let books = [
  { title: 'Title 1', author: 'Author 1', ... },
  { title: 'Title 2', author: 'Author 2', ... },
  { title: 'Title 3', author: 'Author 1', ... },
];
let result = array.select(book => book.author).distinct().toArray();
// ['Author 1', 'Author 2', 'Author 1']
// select + where
let array = [1, 2, 3, 4, 5];
let result = array.where(item => item > 2).select(item => item ** 2).toArray();
// [9, 16, 25]
// select + where + sum
let array = [1, 2, 3, 4, 5];
let result = array.where(item => item > 2).select(item => item ** 2).sum();
// 50
// select + where + aggregate
let array = [1, 2, 3, 4, 5];
let result = array.where(item => item > 2).select(item => item * 2).aggregate((prev, curr) => prev + curr);
// 24
// select + where + take
let array = [1, 2, 3, 4, 5];
let result = array.where(item => item > 2).take(2).select(item => item * 2).toArray();
// [6, 8]
// select + where + take + min
let array = [1, 2, 3, 4, 5];
let result = array.where(item => item > 2).take(2).select(item => item * 2).min();
// 6
// select + where + take + max
let array = [1, 2, 3, 4, 5];
let result = array.where(item => item > 2).take(2).select(item => item * 2).max();
// 8
// skip + take + contains
let array = [1, 2, 3, 4, 5];
let result = array.skip(2).take(2).contains(4);
// true
// selectMany + where
let customers = [
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] },
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] },
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] }
];

let result = customers.selectMany(customer => customer.orders).where(order => order.total > 100).toArray();
// [ { id: 5, total: 200, ... }, { id: 7, total: 150, ... }, { id: 11, total: 250, ... } ]
// selectMany + count
let customers = [
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] },
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] },
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] }
];

let result = customers.selectMany(customer => customer.orders).count(order => order.total > 100);
// 3
// selectMany + select + min
let customers = [
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] },
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] },
  { ..., orders: [ { id, total, ... }, { id, total, ... }, ... ] }
];

let min = customers.selectMany(customer => customer.orders).select(order => order.total).min();
// 150

About

LINQ to JS port using ESnext iterators and generators.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published