Skip to content

Repository files navigation

npmnpm

node-enumerable

ES2017 ready LINQ library written in TypeScript.

Donate

Table of contents

  1. Requirements
  2. Installation
  3. Usage
  4. Playground / demos
  5. Examples
  6. Documentation
  7. License
  8. Tests

Requirements []

Installation []

NodeJS []

Run

npm install node-enumerable --save

inside project folder to install the module.

The module requires at least Node.js 12+.

Browser []

Download the latest version from here.

<html><head><!-- node-enumerable --><scripttype="text/javascript" src="js/enumerable.js"></script></head><body><scripttype="text/javascript">// test codeletseq=Enumerable.create(1,2,3);for(letitemofseq){alert(item);}</script></body></html>

Usage []

Create a sequence []

constEnumerable=require('node-enumerable');function*testGenerator(){yield111;yield222;yield333;}// from a list of values / objects with variable lengthletseq1=Enumerable.create(1,'MK',true,null,{});// from an arrayletseq2=Enumerable.from([11,22,33,44]);// from a generatorletseq3=Enumerable.from(testGenerator());// from a string// // 'A', 'j', 'n', 'a', 't'letseq4=Enumerable.from('Ajnat');// alt: Enumerable.fromString('Ajnat');// range of numbers: 2, 3, 4, 5, 6letseq5=Enumerable.range(2,5);// 5979 'TM' stringsletseq6=Enumerable.repeat('TM',5979);// build, using factory function// // 'item_1', 'item_2', 'item_3'letseq7=Enumerable.build((cancel,index)=>{if(index<3){return'item_'+(index+1);}else{cancel();// we tell that we// want to cancel here}});// build, using factory function// by building a flatten list// // 1, 10, 100, 2, 20, 200, 3, 30, 300letseq8=Enumerable.buildMany((cancel,index)=>{letn=index+1;return[n,n*10,n*100];},3);// create 3 elements// // the 'build()' function has// a same argument// create empty sequenceletseq9=Enumerable.empty();

Work with them []

letseq=Enumerable.create(5979,23979,null,'23979',1781,241279);letnewSeq=seq.where((x)=>x!==null)// remove all elements that are (null).skip(1)// skip one element (5979).take(3)// take next remaining 3 elements (23979, 23979, 1781).distinct()// remove duplicates.select((x)=>""+x)// convert to strings.order();// order by element ascending// you also can use the// 'each' and 'forEach' methods// of the sequence to do the// following jobfor(letitemofnewSeq){// [0] 1781// [1] 23979console.log(item);}

Most methods are chainable as in .NET context.

Async operations []

constFS=require('fs');constPath=require('path');letseq=Enumerable.create('file1.txt','file2.txt','file3.txt','file4.txt');seq.async((context)=>{if(context.isFirst){context.result=0;// initialize a counter// value for the result// s. 'counter' parameter// of then() method below}// [0] file1.txt// [1] file2.txt// [2] file3.txt// [3] file4.txtletfileName=context.item;letfullPath=Path.join(__dirname,fileName);if(context.index<2){FS.readFile(fullPath,(err,data)=>{if(err){context.reject(err);// has to be called if action// FAILED with the error object// or value as argument}else{++context.result;// update counter value// for the result// s. 'counter' of then()// method belowcontext.resolve();// has to be invoked if// invocation was SUCCESSFUL}});}else{context.cancel();// cancel at 3rd element}}).then((counter)=>{// OKconsole.log('Number of loaded files: '+counter);// 2}).catch((err)=>{console.log('One action failed: '+err);});

The context argument of the async() method uses the AsyncActionContext interface.

Playground / demos []

You can test all features in your browser.

Examples []

Filters []

// distinct()// 1, 2, 4, 3Enumerable.create(1,2,4,2,3).distinct();// distinctBy()// "grape", "passionfruit", "banana", "raspberry"Enumerable.create("grape","passionfruit","banana","mango","orange","raspberry","apple","blueberry").distinctBy(x=>x.length);// except()// 2.0, 2.1, 2.3, 2.4, 2.5Enumerable.create(2.0,2.1,2.2,2.3,2.4,2.5).except([2.2]);// intersect()// 26, 30Enumerable.create(44,26,92,30,71,38).intersect([30,59,83,47,26,4,3]);// ofType()// '5979', 'Tanja'Enumerable.create(1,'5979',2,'Tanja',3).ofType('string');// typeof x === 'string'// union()// 5, 3, 9, 7, 8, 6, 4, 1, 0Enumerable.create(5,3,9,7,5,9,3,7).union([8,3,6,4,4,9,1,0]);// where()// 1, 2, 3Enumerable.create(1,2,3,4).where((x)=>x<4);

Sort elements []

// orderBy(), thenBy()//// "apple", "grape", "mango", "banana",// "orange", "blueberry", "raspberry", "passionfruit"Enumerable.create("grape","passionfruit","banana","mango","orange","raspberry","apple","blueberry").orderBy((x)=>x.length)// complement: orderByDescending().thenBy((x)=>x);// complement: thenByDescending()// shorter: then()// reverse()// 4, 3, 2, 1Enumerable.create(1,2,3,4).reverse();// rand()// e.g.: 2, 5, 7, 8, 0, 4, 6, 9, 3, 1Enumerable.range(0,10).rand();// alt: shuffle()

Take / skip elements []

// skip()// 3, 4Enumerable.create(0,1,2,3,4).skip(3);// skipLast()// 0, 1, 2, 3Enumerable.create(0,1,2,3,4).skipLast();// skipWhile()// 55, 666, 77Enumerable.create(22,33,44,55,666,77).skipWhile((x)=>x<50);// take()// 0, 1, 2Enumerable.create(0,1,2,3,4).take(3);// takeWhile()// 22, 33, 44Enumerable.create(22,33,44,55).takeWhile((x)=>x<50);

Get one element []

// elementAt()// 33Enumerable.create(11,22,33,44).elementAt(2);// elementAtOrDefault()// 'TM'Enumerable.create(11,22,33,44).elementAtOrDefault(4,'TM');// out of range// first()// 11Enumerable.create(11,22,33,44).first();// firstOrDefault()// 'MK'Enumerable.create().firstOrDefault('MK');// last()// 44Enumerable.create(11,22,33,44).last();// lastOrDefault()// 'PZ'Enumerable.create().lastOrDefault('PZ');// single()// EXCEPTION, because we have more than one elementEnumerable.create(11,22,33,44).single();// singleOrDefault()// 11Enumerable.create(11).singleOrDefault('YS');

All methods with NO OrDefault suffix will throw exceptions if no element was found.

You also can use a function as first argument for all of these methods that works as filter / condition:

// first()// 22Enumerable.create(11,22,33,44).first((x)=>x>=20);

Accumulators []

// aggregate()// " Marcel Joachim Kloubert"Enumerable.create('Marcel','Joachim','Kloubert').aggregate((accumulator,item)=>{returnaccumulator+=' '+item;},'');// average()// 2.5Enumerable.create(1,2,3,4).average();// "M., Tanja"Enumerable.create('M.','Tanja').joinToString(', ');

Minimum / maximum values []

// max()// 3Enumerable.create(1,3,2).max();// min()// 1Enumerable.create(2,3,1,2).min();

Joins []

classPerson{constructor(name: string){this.name=name;}publicname: string;}classPet{constructor(name: string,owner: Person){this.name=name;this.owner=owner;}publicname: string;publicowner: Person;}letpersons=[newPerson("Tanja"),newPerson("Marcel"),newPerson("Yvonne"),newPerson("Josefine")];letpets=[newPet("Gina",persons[1]),newPet("Schnuffi",persons[1]),newPet("Schnuffel",persons[2]),newPet("WauWau",persons[0]),newPet("Lulu",persons[3]),newPet("Asta",persons[1]),];// groupJoin()// // [0] 'Owner: Tanja; Pets: WauWau, Sparky'// [1] 'Owner: Marcel; Pets: Gina, Schnuffi, Asta'// [2] 'Owner: Yvonne; Pets: Schnuffel'// [3] 'Owner: Josefine; Pets: Lulu'Enumerable.from(persons).groupJoin(pets,(person)=>person.name,(pet)=>pet.owner.name,(person,petsOfPerson)=>{letpetList=petsOfPerson.select(pet=>pet.name).joinToString(', ');return'Owner: '+person.name+'; Pets: '+petList;});// join()// // [0] 'Owner: Tanja; Pet: WauWau'// [1] 'Owner: Marcel; Pet: Gina'// [2] 'Owner: Marcel; Pet: Schnuffi'// [3] 'Owner: Marcel; Pet: Asta'// [4] 'Owner: Yvonne; Pet: Schnuffel'// [5] 'Owner: Josefine; Pet: Lulu'Enumerable.from(persons).join(pets,(person)=>person.name,(pet)=>pet.owner.name,(person,pet)=>{return'Owner: '+person.name+'; Pet: '+pet.name;});

Groupings []

// groupBy()Enumerable.create("grape","passionfruit","blueberry","apple","banana").groupBy(fruit=>fruit[0].toLowerCase()).each((grouping)=>{// grouping[0].key = 'g'// grouping[0][0] = 'grape'// grouping[1].key = 'p'// grouping[1][0] = 'passionfruit'// grouping[2].key = 'b'// grouping[2][0] = 'blueberry'// grouping[2][1] = 'banana'// grouping[3].key = 'a'// grouping[3][0] = 'apple'});

Projection []

// flatten()// 1, (false), 3, 44, '555', 66.6, (true)Enumerable.from([[1,false,3],44,['555',66.6,true]]).flatten();// select()// "MARCEL", "KLOUBERT"Enumerable.create("Marcel","Kloubert").select(x=>x.toUpperCase());// selectMany()// 1, 10, 100, 2, 20, 200, 3, 30, 300Enumerable.create(1,2,3).selectMany(x=>[x,x*10,x*100]);// zip()// "Marcel Kloubert", "Bill Gates", "Albert Einstein"Enumerable.create('Marcel','Bill','Albert').zip(['Kloubert','Gates','Einstein','Adenauer'],(firstName,lastName)=>{return`${firstName}${lastName}`;});

Checks / conditions []

// all()// (false)Enumerable.create(1,2,'3',4).all((x)=>typeofx!=="string");// any()// (true)Enumerable.create(1,2,'3',4).any((x)=>typeofx==="string");// contains()// (true)Enumerable.create(1,2,'3').contains(3);// not()// 1, 2, 4Enumerable.create(1,2,'3',4).not((x)=>typeofx==="string");// sequenceEqual()// (false) Enumerable.create(1,2,3).sequenceEqual([1,3,2]);

Conversions []

// toArray()letjsArray=Enumerable.create(1,2,3,4).toArray();// toObject()letobj=Enumerable.create(1,2,3,4).toObject((item,index)=>"item"+index);// toLookup()// // lookup['A'][0] = 'Albert'// lookup['B'][0] = 'Bill'// lookup['B'][1] = 'barney'// lookup['K'][0] = 'Konrad'// lookup['M'][0] = 'Marcel'letlookup=Enumerable.create('Bill','Marcel','barney','Albert','Konrad').toLookup(x=>x[0].toUpperCase());

Count []

// 3Enumerable.create(0,1,2).count();// a second call will return 0// if reset() method is not called// 2Enumerable.create(0,1,2).count((x)=>x>0);// 4Enumerable.create(11,22,33,44).length();// a second call will return// the same value, because we have an array// based sequence here//// a generator based sequence will behave as count()// (false)Enumerable.create(111,222,333).isEmpty();// all are (false)Enumerable.isNullOrEmpty(Enumerable.create(1111,2222,3333));Enumerable.isUndefinedNullOrEmpty(Enumerable.create(11111,22222,33333));Enumerable.isUndefinedNullOrEmpty(Enumerable.create(0,true,false));

Math []

// abs()// 1, 22.57, 444, NaN, -333.85, NaNEnumerable.create(-1,22.57,444,true,-333.85,false).abs();// ceil()// -1, 23, 444, NaN, -333, NaNEnumerable.create(-1,22.47,444,null,-333.85,false).ceil();// cos()// 0.004, -0.99996, -0.01Enumerable.create(11,22,33).cos();// complement: arcCos()// cosH()// 29937.07, 1792456423.07, 107321789892958.03Enumerable.create(11,22,33).cosH();// complement: arcCosH()// exp()// 2.72, 7.39, 20.09Enumerable.create(1,2,3).exp();// floor()// -1, 23, 444, NaN, -334, NaNEnumerable.create(-1,22.47,444.0,undefined,-333.85,true).floor();// log()// 0, 1, 2, 3, 4Enumerable.create(1,2,4,8,16).log(2);// pow()// 1, 4, 9, 16Enumerable.create(1,2,3,4).pow(2);// product()// 24Enumerable.create(1,2,3,4).product();// root()// 1, 2, 3, 4Enumerable.create(1,8,27,64).root(3);// round()// -1, 23, 444, NaN, -334, 2, NaNEnumerable.create(-1,22.47,444.0,undefined,-333.85,1.5,true).round();// sin()// 0.84, 0.91, 0.14Enumerable.create(1,2,3).sin();// complement: arcSin()// sinH()// 1.18, 3.63, 10.02Enumerable.create(1,2,3).sinH();// complement: arcSinH()// sqrt()// 1, 2, 3, 4Enumerable.create(1,4,9,16).sqrt();// sum()// 10Enumerable.create(1,2,3,4).sum();// tan()// 1.72, -1.76, -0.01Enumerable.create(111,222,333).tan();// complement: arcTan()// tanH()// 0, 0.46, -0.76Enumerable.create(0,0.5,-1).tanH();// complement: arcTanH()

More []

assert []

letseq1=Enumerable.range(0,10);seq1.assert((x)=>{returnx%2!==1;});// will throw an exception// at second element (1)letseq2=Enumerable.range(0,10);seq2.assertAll((x)=>{returnx%2!==1;});// will throw an aggregated exception// at the end// for all odd values

chunk []

letseq=Enumerable.range(0,10);for(letchunkofseq.chunk(3)){// [0] => [0, 1, 2]// [1] => [3, 4, 5]// [2] => [6, 7, 8]// [3] => [9]}

clone []

letfather=Enumerable.create(0,1,2);// create 3 clones of 'father'for(letchildoffather.clone(3)){//TODO}// alt: father.clone().take(3)

concat / concatArray []

// 0, 1, 2, 'PZ', 'TM', 'MK'Enumerable.create(0,1,2).concat(['PZ'],['TM','MK']);// alt: append()// 0, 111, 222, 'pz', 'tm', 'mk'Enumerable.create(0,111,222).concatArray([['pz','tm'],['mk']]);// alt: appendArray()

consume []

functioncreateIteratorAndStorage(size){letstorage=[];return{iterator: makeIterator(size,storage),storage: storage,};}function*makeIterator(size,storage){for(leti=0;i<size;i++){yieldi;storage.push(i);}}constOBJ=createIteratorAndStorage(100);constSEQ=Enumerable.from(OBJ.iterator);SEQ.consume();// enumerates the 'iterator' in OBJ// and fills the 'storage' in OBJ

defaultIfEmpty / defaultArrayIfEmpty []

// 0, 1, 2Enumerable.create(0,1,2).defaultIfEmpty('PZ','TM','MK');// 'PZ', 'TM', 'MK'Enumerable.empty().defaultIfEmpty('PZ','TM','MK');// 0, 11, 22Enumerable.create(0,11,22).defaultArrayIfEmpty(['pz','tm','mk']);// alt: defaultSequenceIfEmpty()// 'pz', 'tm', 'mk'Enumerable.empty().defaultArrayIfEmpty(['pz','tm','mk']);

forAll []

letarr=[];try{// alt: eachAll()Enumerable.range(0,5).forAll(x=>{if(x%2===0){throw'Error in value '+x;}arr.push(x);});}catch(e){// access the list of errors by// 'e.errors'// e.errors[0] = 'Error in value 0';// e.errors[1] = 'Error in value 2';// e.errors[2] = 'Error in value 3';}// arr[0] === 1// arr[1] === 3// arr[2] === 5

intersperse / intersperseArray []

// 0, '-', 1, '-', 2Enumerable.range(0,3).intersperse('-');// -- or --Enumerable.range(0,3).intersperseArray(['-']);

pipe []

letarr1=[];letarr2=[];letseq=Enumerable.create(1,2,3).pipe((x)=>{arr1.push(x*10);});for(letitemofseq){arr2.push(item);}// arr1 = [10, 20, 30]// arr2 = [1, 2, 3]

popFrom / shiftFrom []

letarr1=[11,22,33];for(letitemofEnumerable.popFrom(arr1)){// [0] 33// [1] 22// [2] 11}// arr1 is empty nowletarr2=[111,222,333];for(letitemofEnumerable.shiftFrom(arr2)){// [0] 111// [1] 222// [2] 333}// arr2 is empty now

prepend / prependArray []

// 'PZ', 'TM', 'MK', 0, 1, 2Enumerable.create(0,1,2).prepend(['PZ'],['TM','MK']);// 'pz', 'tm', 'mk', 0, 111, 222Enumerable.create(0,111,222).prependArray([['pz','tm'],['mk']]);

pushTo []

letarr=[];Enumerable.create(0,1,2).pushTo(arr);// arr: [0, 1, 2]

random []

for(letvalueofEnumerable.random(10)){// 10 random numbers// between 0 and 1}for(letvalueofEnumerable.random(23979,v=>v*5979)){// 23979 random numbers// between 0 and 5979}

reset []

letseq=Enumerable.create(0,1,2);seq.each(x=>{console.log(x);});seq.reset().each(x=>{console.log(x*2);});

trace []

// write items via 'console.trace()'Enumerable.create(0,1,2).trace();// with formatterEnumerable.create(1.2,2.3,3.45).trace(x=>'Item: '+x);

Documentation []

The API documentation can be found here.

License []

MIT license

Tests []

Go to the module folder and run

tsc
npm test

to start unit tests from test/ subfolder.

Releases

Sponsor this project

Packages

Used by

Contributors

Languages