@berish/linq
Library for convenient work with arrays. Allows you to make convenient sampling, and work with arrays as usual. It is a direct inheritor from the array, which allows you to work with linq as with a regular array.
Installation
$ npm install @berish/linq --save
or
$ yarn add @berish/linq
Supports typescript
Interfaces
type CallbackType<T, Response> = (item: T, index: number, linq: LINQ<T>) => Response;
type CallbackWithAccumType<T, Accum, Response> = (item: T, index: number, linq: LINQ<T>, accum: Accum) => Response;
type CallbackOnlyItemType<T, Response> = (item: T) => Response;
Initialize (from method)
Syntax: public static from<T>(items?: T[]): LINQ<T>
Example:
import LINQ from '@berish/linq';
const linq = LINQ.from(array);
Test dataset for examples in this article:
import LINQ from '@berish/linq';
import * as collection from 'berish-collection';
import * as faker from 'faker';
class TestAType {}
class TestBType {}
function generateCard(index: number = 0) {
return {
age: faker.random.number({ min: 0, max: 30 }),
email: faker.internet.email(),
id: faker.random.uuid(),
rating: faker.random.number({ min: 0, max: 100 }),
types: index % 2 === 0 ? new TestAType() : new TestBType(),
};
}
function getLinq(count: number = 10) {
const data = Array(count)
.fill(null)
.map((m, i) => generateCard(i));
return LINQ.from(data);
}
clone
Makes no deep clone for current LINQ array.
Syntax: public clone(): LINQ<T>
Example:
const linq1 = LINQ.from([1, 2, 3]);
const cloned = linq1.clone();
expect(cloned).toEqual(linq1);
expect(cloned === linq1).toBeFalsy();
equals
Check equals this LINQ and another array by link-pointer
Syntax: public equals(linq: any[]): boolean
Example:
const linq1 = LINQ.from([1, 2, 3]);
const cloned = linq1.clone();
expect(linq1.equals(cloned)).toBeFalsy();
expect(linq1.equals(linq1)).toBeTruthy();
equalsValues
Check equals this LINQ and another array by values. You can map a sequence of values based on a predicate.
Syntax: public equalsValues<K>(linq: any[], selectFunc?: CallbackType<T, K>): boolean
Example:
const linq1 = LINQ.from([1, 2, 3]);
const cloned = linq1.clone();
expect(linq1.equalsValues(cloned)).toBeTruthy();
expect(linq1.equalsValues(linq1)).toBeTruthy();
const linq2 = LINQ.from([{ id: 1 }, { id: 2 }, { id: 3 }]);
const linq3 = [{ id: 1 }, { id: 2 }, { id: 3 }];
expect(linq2.equalsValues(linq3)).toBeFalsy();
expect(linq2.equalsValues(linq3, m => m.id)).toBeTruthy();
where
Filters a sequence of values based on a predicate.
Syntax: public where(whereFunc?: CallbackType<T, boolean>): LINQ<T>
Example:
const linq = getLinq();
expect(linq.where(m => m.age % 2 === 0)).toEqual(linq.filter(m => m.age % 2 === 0));
whereWithAccum
Allows you to narrow the LINQ on a specific condition on the elements of this LINQ (selectFunc and whereSelectedFunc). It is also possible to accumulate any value (accumFunc) for later use in the condition (whereSelectedFunc)
Syntax: public whereWithAccum<K, Accum = LINQ<K>>( selectFunc: CallbackType<T, K>, accumFunc: (selected: LINQ<K>, linq: LINQ<T>) => Accum, whereSelectedFunc: CallbackWithAccumType<K, Accum, boolean>, ): LINQ<T>
Example:
const linq = getLinq();
const where = linq.whereWithAccum(m => m.age, selected => Math.max(...selected), (m, i, l, max) => m >= max);
const max = Math.max(...linq.map(m => m.age));
const maxWhere = linq.where(m => m.age === max);
expect(where).toEqual(maxWhere);
select
Calls a defined selectFunc on each element of an LINQ, and returns an LINQ that contains the results. It's analog for array map method
Syntax: public select<K>(selectFunc: CallbackType<T, K>): LINQ<K>
Example:
const linq = getLinq();
const selected = linq.select(m => m.email);
const mapped = linq.map(m => m.email);
expect(selected).toEqual(mapped);
selectMany
Projects each element of a sequence to an LINQ and flattens the resulting sequences into one sequence.
Syntax: public selectMany<K>(selectFunc?: CallbackType<T, K[]>): LINQ<K>
Example:
const linq = LINQ.from([getLinq(), getLinq(), getLinq()]);
const selected1 = linq.selectMany();
expect(selected1).toEqual([...linq[0], ...linq[1], ...linq[2]]);
const selected2 = linq.selectMany(m => m.select(m => m.id));
expect(selected2).toEqual([...linq[0].select(m => m.id), ...linq[1].select(m => m.id), ...linq[2].select(m => m.id)]);
take
Returns a specified number of contiguous elements from the start of a sequence.
Syntax: public take(count: number): LINQ<T>
Example:
const linq = getLinq(50);
const take = linq.take(20);
expect(take.length).toBe(20);
expect(take).toEqual(linq.slice(0, 20));
skip
Bypasses a specified number of elements in a sequence and then returns the remaining elements.
Syntax: public skip(count: number): LINQ<T>
Example:
const linq = getLinq(100);
const skip = linq.skip(20);
expect(skip.length).toBe(80);
expect(skip).toEqual(linq.slice(20));
count
Returns the number of elements in a sequence.
Syntax: public count(whereFunc?: CallbackType<T, boolean>): number
Example:
const linq = getLinq(100);
const count1 = linq.count();
expect(count1).toBe(100);
const count2 = linq.count(m => m.age % 2 === 0);
expect(count2).toBe(linq.where(m => m.age % 2 === 0).count());
indexWhere
Returns the indexes of elements in a sequence by whereFunc
Syntax: public indexWhere(whereFunc?: CallbackType<T, boolean>): LINQ<number>
Example:
const linq = getLinq();
const indexWhere = linq.indexWhere(m => m.age % 2 === 0);
expect(indexWhere).toEqual(linq.select((m, i) => (m.age % 2 === 0 ? i : null)).notNull());
elementsAtIndex
Returns elements in LINQ by indexes of this elements
Syntax: public elementsAtIndex(indexes: number[]): LINQ<T>
Example:
const linq = getLinq();
const elementsAtIndex = linq.elementsAtIndex([0, 5, 8, 12]);
expect(elementsAtIndex.length).toBe(4);
expect(elementsAtIndex).toEqual([linq[0], linq[5], linq[8], linq[12]]);
notNull
Return only not null elements. Can be using with the selectFunc to filtered elements from a sequence by mapped values.
Syntax: public notNull<K>(selectFunc?: CallbackType<T, K>): LINQ<T>
Example:
const linq = getLinq(100);
const notNull = linq.select((m, i) => (i % 2 === 0 ? m : null)).notNull();
expect(notNull.length).toBe(50);
expect(notNull).toEqual(linq.where((m, i) => i % 2 === 0));
notEmpty
Return only not empty elements (!!value). Can be using with the selectFunc to filtered elements from a sequence by mapped values.
Syntax: public notEmpty<K>(selectFunc?: CallbackType<T, K>): LINQ<T>
Example:
const linq = getLinq(100);
const notEmpty = linq.select((m, i) => (i % 2 === 0 ? m : '')).notEmpty();
expect(notEmpty.length).toBe(50);
expect(notEmpty).toEqual(linq.where((m, i) => i % 2 === 0));
first
Returns the first element in a sequence that satisfies a specified condition.
Syntax: public first(whereFunc?: CallbackType<T, boolean>): T
Example:
const linq = getLinq();
const first1 = linq.first();
expect(first1).toBe(linq[0]);
const first2 = linq.first(m => m.age % 2 === 0);
expect(first2).toBe(linq.where(m => m.age % 2 === 0).first());
last
Returns the last element in a sequence that satisfies a specified condition.
Syntax: public last(whereFunc?: CallbackType<T, boolean>): T
Example:
const linq = getLinq();
const last1 = linq.last();
expect(last1).toBe(linq[linq.length - 1]);
const last2 = linq.last(m => m.age % 2 === 0);
expect(last2).toBe(linq.where(m => m.age % 2 === 0).last());
distinct
Returns distinct elements from a sequence. Can be using with the selectFunc to filtered elements from a sequence by mapped values.
Syntax: public distinct<K>(selectFunc?: CallbackType<T, K>): LINQ<T>
Example:
const linq = getLinq(100);
const distinct1 = linq.select(m => m.age).distinct();
expect(distinct1.length).toBe(new Set(linq.select(m => m.age)).size);
const distinct2 = linq.distinct(m => m.age);
const addedAges: number[] = [];
const testDistinct2 = linq.where(m => {
if (addedAges.indexOf(m.age) === -1) {
addedAges.push(m.age);
return true;
}
return false;
});
expect(distinct2).toEqual(testDistinct2);
max
Returns the elements with maximum value in a sequence of values.
Syntax: public max(numberFunc?: CallbackType<T, number>): LINQ<T>
Example:
const linq = getLinq();
const max = linq.max(m => m.age);
const maxValue = Math.max(...linq.select(m => m.age));
expect(max).toEqual(linq.where(m => m.age === maxValue));
maxValue
Returns the maximum value in a sequence of values.
Syntax: public maxValue(numberFunc?: CallbackType<T, number>): number
Example:
const linq = getLinq();
const maxValue = linq.maxValue(m => m.age);
expect(maxValue).toBe(Math.max(...linq.select(m => m.age)));
min
Returns the elements with minimum value in a sequence of values.
Syntax: public min(numberFunc?: CallbackType<T, number>): LINQ<T>
Example:
const linq = getLinq();
const min = linq.min(m => m.age);
const minValue = Math.min(...linq.select(m => m.age));
expect(min).toEqual(linq.where(m => m.age === minValue));
minValue
Returns the minimum value in a sequence of values.
Syntax: public minValue(numberFunc?: CallbackType<T, number>): number
Example:
const linq = getLinq();
const minValue = linq.minValue(m => m.age);
expect(minValue).toBe(Math.min(...linq.select(m => m.age)));
ofType
Filters the elements of a LINQ based on a specified types. Can be using with the selectFunc to filtered elements from a sequence by mapped values.
Syntax: public ofType<Type extends new (...args) => any, K>( type: OfTypeStringValues | OfTypeStringValues[] | Type | Type[] | (OfTypeStringValues | Type)[], selectFunc?: CallbackType<T, K>, ): LINQ<T>
type OfTypeStringValues = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function';
Example:
const linq = getLinq();
const ofType1 = linq.ofType(Object);
expect(ofType1).toEqual(linq);
const ofType2 = linq.ofType(TestAType, m => m.types);
expect(ofType2).toEqual(linq.where(m => m.types instanceof TestAType));
const ofType3 = linq.ofType([TestAType, TestBType], m => m.types);
expect(ofType3).toEqual(linq);
const ofType4 = linq.ofType('number', m => m.age);
expect(ofType4.count()).toBe(linq.count());
const ofType5 = linq.ofType('string', m => m.age);
expect(ofType5.count()).toBe(0);
orderByAscending
Sorts the elements of a sequence in ascending order according to a value. Can be using with the sortSelectFunc to order elements from a sequence by mapped values.
Syntax: public orderByAscending<K>(sortSelectFunc?: CallbackOnlyItemType<T, K>): LINQ<T>
Example:
const linq1 = LINQ.from([4, 2, 1, 5, 8, -1]);
const orderByAscending1 = linq1.orderByAscending();
expect(orderByAscending1).toEqual([-1, 1, 2, 4, 5, 8]);
const linq2 = getLinq();
const orderByAscending2 = linq2.orderByAscending(m => m.age);
const bySort2 = linq2.sort((a, b) => {
if (a.age > b.age) return 1;
if (a.age < b.age) return -1;
return 0;
});
expect(orderByAscending2).toEqual(bySort2);
orderByDescending
Sorts the elements of a sequence in descending order according to a value. Can be using with the sortSelectFunc to order elements from a sequence by mapped values.
Syntax: public orderByDescending<K>(sortSelectFunc?: CallbackOnlyItemType<T, K>): LINQ<T>
Example:
const linq1 = LINQ.from([4, 2, 1, 5, 8, -1]);
const orderByDescending1 = linq1.orderByDescending();
expect(orderByDescending1).toEqual([8, 5, 4, 2, 1, -1]);
const linq2 = getLinq();
const orderByDescending2 = linq2.orderByDescending(m => m.age);
const bySort2 = linq2.sort((a, b) => {
if (a.age < b.age) return 1;
if (a.age > b.age) return -1;
return 0;
});
expect(orderByDescending2).toEqual(bySort2);
sum
Computes the sum of a sequence of numeric values. Can be using with the selectFunc to sum elements from a sequence by mapped values.
Syntax: public sum(selectFunc?: CallbackType<T, number>): number
Example:
const linq1 = LINQ.from([4, 2, 1, 5, 8, -1]);
const sum1 = linq1.sum();
expect(sum1).toBe(linq1.reduce((a, b) => a + b, 0));
const linq2 = getLinq();
const sum2 = linq2.sum(m => m.age);
expect(sum2).toBe(linq2.select(m => m.age).reduce((a, b) => a + b, 0));
except
Produces the set difference of two sequences. Can be using with the selectFunc to except elements from a sequence by mapped values.
Syntax: public except<K>(items: T | T[] | LINQ<T>, selectFunc?: CallbackType<T, K>): LINQ<T>
Example:
const linq1 = LINQ.from([4, 2, 1, 5, 8, -1]);
const linq2 = LINQ.from([4, -100, 7, 5, 8, -1]);
const expect1 = linq1.except(linq2);
expect(expect1).toEqual([2, 1]);
const linq3 = getLinq(100);
const linq4 = getLinq(100);
const expect2 = linq3.except(linq4);
expect(expect2).toEqual(linq3);
const expect3 = linq3.except(linq4, m => m.age);
expect(expect3).toEqual(linq3.where(m => !linq4.contains(m, k => k.age)));
groupBy
Groups the elements of a sequence according to a specified key selector function and creates a result value from each group and its key. The elements of each group are projected by using a specified function selectFunc.
Syntax: public groupBy<K>(selectFunc: CallbackType<T, K>): collection.Dictionary<K, LINQ<T>>
Example:
const linq = getLinq();
const dict1 = linq.groupBy(m => m.age);
const ages = linq.select(m => m.age).distinct();
const dict2 = collection.Dictionary.fromArray(
ages.select(m => new collection.KeyValuePair(m, linq.where(k => k.age === m))),
);
expect(dict1).toEqual(dict2);
contains
Determines whether a sequence contains a specified element. Can be using with the selectFunc to check for contain elements from a sequence by mapped values.
Syntax: public contains<K>(value: T, selectFunc?: CallbackOnlyItemType<T, K>): boolean
Example:
const linq1 = LINQ.from(['hey', 'bro']);
expect(linq1.contains('hey')).toBeTruthy();
expect(linq1.contains('hello')).toBeFalsy();
const linq2 = getLinq(100);
expect(linq2.contains(linq2[0])).toBeTruthy();
let card = generateCard();
while (!linq2.first(m => m.age === card.age)) {
card = generateCard();
}
expect(linq2.contains(card)).toBeFalsy();
expect(linq2.contains(card, m => m.age)).toBeTruthy();
containsAll
Determines whether a sequence contains all of the specified elements at once. Can be using with the selectFunc to check for contain elements from a sequence by mapped values.
Syntax: public containsAll<K>(value: T[] | LINQ<T>, selectFunc?: CallbackType<T, K>): boolean
Example:
const linq1 = LINQ.from(['hey', 'bro']);
expect(linq1.containsAll(['hey', 'bro'])).toBeTruthy();
expect(linq1.containsAll(['hey', 'hello'])).toBeFalsy();
const linq2 = getLinq(100);
expect(linq2.containsAll([linq2.first(), linq2.last()])).toBeTruthy();
let card1 = generateCard();
while (!linq2.first(m => m.age === card1.age)) {
card1 = generateCard();
}
let card2 = generateCard();
while (!linq2.first(m => m.age === card2.age)) {
card2 = generateCard();
}
expect(linq2.containsAll([card1, card2])).toBeFalsy();
expect(linq2.containsAll([card1, card2], m => m.age)).toBeTruthy();
average
Computes the average of a sequence of numeric values. Can be using with the selectFunc to average elements from a sequence by mapped values. Can be using with the whereFunc to filter elements from a sequence by specified condition.
Syntax: public average(selectFunc?: CallbackType<T, number>, whereFunc?: CallbackType<T, boolean>): number
Example:
const linq1 = LINQ.from([1, 2, 5, 10]);
expect(linq1.average()).toBe(4.5);
expect(linq1.average(null, m => m % 2 === 0)).toBe(6);
const linq2 = getLinq();
expect(linq2.average(m => m.age)).toBe(linq2.select(m => m.age).average());
expect(linq2.average(m => m.rating, m => m.age > 18)).toBe(
linq2
.where(m => m.age > 18)
.select(m => m.rating)
.average(),
);
intersect
Produces the set intersection of two sequences. Can be using with the selectFunc to intersect elements from a sequence by mapped values.
Syntax: public intersect<K>(items: T | T[] | LINQ<T>, selectFunc?: CallbackType<T, K>): LINQ<T>
Example:
const linq1 = LINQ.from([4, 2, 1, 5, 8, -1]);
const linq2 = LINQ.from([4, -100, 7, 5, 8, -1]);
const intersect1 = linq1.intersect(linq2);
expect(intersect1).toEqual([4, 5, 8, -1]);
const linq3 = getLinq(100);
const linq4 = getLinq(100);
const intersect2 = linq3.intersect(linq4);
expect(intersect2).toEqual([]);
const intersect3 = linq3.intersect(linq4, m => m.age);
expect(intersect3).toEqual(linq3.where(m => linq4.contains(m, k => k.age)));
reverse
Reverses the elements in an Array.
Syntax: public reverse(): LINQ<T>
Example:
const linq = LINQ.from([1, 4, 2, 3, 3]);
expect(linq.reverse()).toEqual([3, 3, 2, 4, 1]);
concat
Combines two or more arrays. Combines two or more arrays.
Syntax: public concat(...items: (T | ConcatArray<T> | LINQ<T>)[]): LINQ<T>
Example:
const linq1 = LINQ.from([1, 4, 3]);
const linq2 = LINQ.from([2, 3, 3]);
expect(linq1.concat(linq2)).toEqual([1, 4, 3, 2, 3, 3]);
slice
Returns a section of an array.
Syntax: public slice(start?: number, end?: number): LINQ<T>
Example:
const linq = LINQ.from([1, 4, 2, 3, 3]);
expect(linq.slice(2, 4)).toEqual([2, 3]);
splice
Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
Syntax: public splice(start: number, deleteCount: number, ...items: T[]): LINQ<T>
Example:
const linq = getLinq();
const cloned = linq.clone();
cloned.splice(0, 3);
expect(cloned).toEqual(linq.skip(3));
map
Calls a defined callback function on each element of an array, and returns an array that contains the results.
Syntax: public map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): LINQ<U>
Example:
const linq = LINQ.from([{ id: 1 }, { id: 2 }]);
expect(linq.map(m => m.id)).toEqual([1, 2]);
filter
Returns the elements of an array that meet the condition specified in a callback function. Returns the elements of an array that meet the condition specified in a callback function.
Syntax: public filter(callbackfn: (value: T, index: number, array: T[]) => unknown, thisArg?: any): LINQ<T>
Example:
const linq = LINQ.from([{ id: 1 }, { id: 2 }]);
expect(linq.filter(m => m.id > 1)).toEqual([{ id: 2 }]);