├── .gitattributes ├── bower.json ├── package.json ├── .gitignore ├── src ├── spec │ ├── linq.helper.spec.js │ ├── mergeSort.spec.js │ ├── linq.chain.spec.js │ └── linq.eval.spec.js └── linq.js ├── gulpfile.js ├── index.d.ts ├── README.md └── linq-browser.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazy-linq", 3 | "version": "1.0.2", 4 | "authors": [ 5 | "anstinus " 6 | ], 7 | "description": "A full port of LINQ for javascript. It works fully in 'lazy' mode for the best performance.", 8 | "main": "linq-browser.js", 9 | "keywords": [ 10 | "linq", 11 | "lazy", 12 | "deferred", 13 | "performance", 14 | "algorithm" 15 | ], 16 | "license": "MIT", 17 | "moduleType": [ 18 | "amd", 19 | "es6", 20 | "globals", 21 | "node" 22 | ], 23 | "homepage": "https://github.com/Anstinus/lazy-linq/", 24 | "repository": { 25 | "type": "git", 26 | "url": "git://github.com/Anstinus/lazy-linq.git" 27 | }, 28 | "ignore": [ 29 | "**/.*", 30 | "node_modules", 31 | "bower_components", 32 | "test", 33 | "tests", 34 | ".tmp", 35 | "src", 36 | "linq.js", 37 | "gulpfile.js" 38 | ], 39 | "dependencies": { 40 | "babel-polyfill": "~0.0.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazy-linq", 3 | "version": "1.0.3", 4 | "description": "A full port of LINQ for javascript. It works fully in 'lazy' mode for the best performance.", 5 | "main": "linq.js", 6 | "scripts": { 7 | "test": "gulp test:es5", 8 | "build": "gulp build" 9 | }, 10 | "homepage": "https://github.com/Anstinus/lazy-linq/", 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/Anstinus/lazy-linq.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/Anstinus/lazy-linq/issues" 17 | }, 18 | "keywords": [ 19 | "linq", 20 | "lazy", 21 | "deferred", 22 | "performance", 23 | "algorithm" 24 | ], 25 | "author": { 26 | "name": "anstinus", 27 | "email": "anstinus@gmail.com" 28 | }, 29 | "license": "MIT", 30 | "devDependencies": { 31 | "babel": "^5.6.14", 32 | "del": "^1.2.0", 33 | "esperanto": "^0.7.3", 34 | "gulp": "^3.9.0", 35 | "gulp-babel": "^5.1.0", 36 | "gulp-concat": "^2.6.0", 37 | "gulp-jasmine": "^2.0.1", 38 | "gulp-rename": "^1.2.2", 39 | "jasmine": "^2.3.1" 40 | }, 41 | "dependencies": { 42 | "babel-runtime": "^5.6.17" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | .tmp 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directory 24 | # Commenting this out is preferred by some people, see 25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 26 | node_modules 27 | bower_components 28 | 29 | # Users Environment Variables 30 | .lock-wscript 31 | 32 | # ========================= 33 | # Operating System Files 34 | # ========================= 35 | 36 | # OSX 37 | # ========================= 38 | 39 | .DS_Store 40 | .AppleDouble 41 | .LSOverride 42 | 43 | # Thumbnails 44 | ._* 45 | 46 | # Files that might appear on external disk 47 | .Spotlight-V100 48 | .Trashes 49 | 50 | # Directories potentially created on remote AFP share 51 | .AppleDB 52 | .AppleDesktop 53 | Network Trash Folder 54 | Temporary Items 55 | .apdisk 56 | 57 | # Windows 58 | # ========================= 59 | 60 | # Windows image file caches 61 | Thumbs.db 62 | ehthumbs.db 63 | 64 | # Folder config file 65 | Desktop.ini 66 | 67 | # Recycle Bin used on file shares 68 | $RECYCLE.BIN/ 69 | 70 | # Windows Installer files 71 | *.cab 72 | *.msi 73 | *.msm 74 | *.msp 75 | 76 | # Windows shortcuts 77 | *.lnk 78 | -------------------------------------------------------------------------------- /src/spec/linq.helper.spec.js: -------------------------------------------------------------------------------- 1 | import * as linq from '../linq'; 2 | 3 | linq.installAsEnumerable(); 4 | 5 | describe('linq lib -> helper function ->', function () { 6 | describe('range()', function () { 7 | it('should generate incremental sequence', function () { 8 | expect(linq.range(1, 3).toArray()).toEqual([1, 2, 3]); 9 | }); 10 | 11 | it('with @count == 0 should generate empty sequence', function () { 12 | expect(linq.range(1, 0).toArray().length).toBe(0); 13 | }); 14 | 15 | it('with @count < 0 should generate empty sequence', function () { 16 | expect(linq.range(1, -1).toArray().length).toBe(0); 17 | }); 18 | 19 | it('toArray() again on the same range() should generate the same result', function () { 20 | let data = linq.range(1, 3); 21 | expect(data.toArray()).toEqual([1, 2, 3]); 22 | expect(data.toArray()).toEqual([1, 2, 3]); 23 | }); 24 | }); 25 | 26 | describe('repeat()', function () { 27 | it('should generate identical sequence', function () { 28 | expect(linq.repeat(1, 3).toArray()).toEqual([1, 1, 1]); 29 | }); 30 | 31 | it('with @count == 0 should generate empty sequence', function () { 32 | expect(linq.repeat(1, 0).toArray().length).toBe(0); 33 | }); 34 | 35 | it('with @count < 0 should generate empty sequence', function () { 36 | expect(linq.repeat(1, -1).toArray().length).toBe(0); 37 | }); 38 | 39 | it('toArray() again on the same repeat() should generate the same result', function () { 40 | let data = linq.repeat(1, 3); 41 | expect(data.toArray()).toEqual([1, 1, 1]); 42 | expect(data.toArray()).toEqual([1, 1, 1]); 43 | }); 44 | }); 45 | 46 | describe('empty()', function () { 47 | it('should be empty', function () { 48 | expect(linq.empty().toArray().length).toBe(0); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var babel = require('gulp-babel'); 3 | var del = require('del'); 4 | var rename = require('gulp-rename'); 5 | var jasmine = require('gulp-jasmine'); 6 | var concat = require('gulp-concat'); 7 | 8 | function getBabelOption(isForBrower) { 9 | var babelOption = { 10 | loose: 'all', 11 | modules: 'umd', 12 | comments: false 13 | }; 14 | if (!isForBrower) { 15 | babelOption.optional = ['runtime']; 16 | } 17 | return babelOption; 18 | } 19 | 20 | gulp.task('build:node', ['clean'], function () { 21 | return gulp.src('src/linq.js') 22 | .pipe(babel(getBabelOption(false))) 23 | .pipe(gulp.dest('.')); 24 | }); 25 | 26 | gulp.task('build:browser', ['clean'], function () { 27 | return gulp.src('src/linq.js') 28 | .pipe(babel(getBabelOption(true))) 29 | .pipe(rename('linq-browser.js')) 30 | .pipe(gulp.dest('.')); 31 | }); 32 | 33 | gulp.task('build', ['build:node', 'build:browser']); 34 | 35 | gulp.task('clean', function () { 36 | return del(['linq*.js']); 37 | }); 38 | 39 | gulp.task('test', function (done) { 40 | require("babel/register"); 41 | 42 | return gulp.src('src/**/*.js') 43 | .pipe(jasmine()); 44 | }); 45 | 46 | gulp.task('test:auto', function (done) { 47 | var watcher = gulp.watch('src/**/*.js', ['test']); 48 | watcher.on('change', function (event) { 49 | process.stdout.write('\033c'); 50 | console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); 51 | }); 52 | gulp.start('test'); 53 | }); 54 | 55 | gulp.task('clean:tmp', function () { 56 | return del('.tmp/**/*'); 57 | }); 58 | 59 | gulp.task('test:es5', ['clean:tmp'], function (done) { 60 | gulp.src('src/**/*.js') 61 | .pipe(babel(getBabelOption(false))) 62 | .pipe(gulp.dest('.tmp')) 63 | .pipe(jasmine()); 64 | }) 65 | 66 | gulp.task('default', ['build'], function () {}); 67 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | type Predicate = (item: T) => boolean; 2 | type Func = () => TResult; 3 | type Func1 = (x: T1) => TResult; 4 | type Func2 = (x1: T1, x2: T2) => TResult; 5 | type Func3 = (x1: T1, x2: T2, x3: T3) => TResult; 6 | type Func4 = ( 7 | x1: T1, 8 | y1: T2, 9 | x3: T3, 10 | x4: T4 11 | ) => TResult; 12 | 13 | interface IGrouping extends IEnumerable { 14 | key: TKey; 15 | } 16 | 17 | interface IOrderedEnumerable extends IEnumerable {} 18 | 19 | interface IEnumerable { 20 | skip(count: number): IEnumerable; 21 | skipWhile(pred: Predicate): IEnumerable; 22 | take(count: number): IEnumerable; 23 | takeWhile(pred: Predicate): IEnumerable; 24 | reverse(): IEnumerable; 25 | select(selector: Func1): IEnumerable; 26 | where(pred: Predicate): IEnumerable; 27 | selectMany( 28 | selector: Func1> 29 | ): IEnumerable; 30 | groupBy( 31 | keySelector: Func1 32 | ): IEnumerable>; 33 | orderBy(keySelector: Func1): IOrderedEnumerable; 34 | orderByDescending( 35 | keySelector: Func1 36 | ): IOrderedEnumerable; 37 | thenBy(keySelector: Func1): IOrderedEnumerable; 38 | thenByDescending( 39 | keySelector: Func1 40 | ): IOrderedEnumerable; 41 | join( 42 | inner: IEnumerable, 43 | outerKeySelector: Func1, 44 | innerKeySelector: Func1, 45 | resultSelector: Func2 46 | ): IEnumerable; 47 | groupJoin( 48 | inner: IEnumerable, 49 | outerKeySelector: Func1, 50 | innerKeySelector: Func1, 51 | resultSelector: Func2, TResult> 52 | ): IEnumerable; 53 | zip( 54 | second: IEnumerable, 55 | resultSelector: Func2 56 | ): IEnumerable; 57 | concat(second: IEnumerable): IEnumerable; 58 | distinct(): IEnumerable; 59 | union(second: IEnumerable): IEnumerable; 60 | intersect(second: IEnumerable): IEnumerable; 61 | except(second: IEnumerable): IEnumerable; 62 | all(pred: Predicate): boolean; 63 | any(pred: Predicate): boolean; 64 | singleOrDefault(): TSource | undefined; 65 | single(): TSource; 66 | count(pred: Predicate): number; 67 | contains(value: TSource): boolean; 68 | elementAtOrDefault(index: number): TSource | undefined; 69 | elementAt(index: number): TSource; 70 | firstAtOrDefault(index: number): TSource | undefined; 71 | firstAt(index: number): TSource; 72 | first(pred?: Predicate): TSource; 73 | lastAtOrDefault(index: number): TSource | undefined; 74 | lastAt(index: number): TSource; 75 | last(pred?: Predicate): TSource; 76 | defaultIfEmpty(val: TSource): IEnumerable; 77 | sequenceEqual(second: IEnumerable): boolean; 78 | min(keySelector?: Func1): TSource; 79 | max(keySelector?: Func1): TSource; 80 | sum(keySelector?: Func1): TSource; 81 | average(keySelector?: Func1): TSource; 82 | aggregate(func: Func2): TSource; 83 | toArray(): TSource[]; 84 | toSet(): Set; 85 | toMap( 86 | keySelector: Func1, 87 | valSelector: Func1 88 | ): Map; 89 | forEach(iterFn: (source: TSource) => void): void; 90 | } 91 | 92 | interface LazyLinq { 93 | asEnumerable(list: T[]): IEnumerable; 94 | } 95 | 96 | declare const LazyLinq: LazyLinq; 97 | 98 | declare module "lazy-linq" { 99 | export = LazyLinq; 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lazy-linq 2 | A full port of LINQ for javascript. It works fully in 'lazy' mode for the best performance. 3 | 4 | ## Introduction 5 | This library is written in ES6 and transpiled using Babel. It implements all API from .Net static class `System.Linq.Enumerable`. 6 | 7 | By levering the power of `generator` in ES6, this library works in a lazy(or deferred) way as in .NET -- Instead of doing computing on the whole sequence at once, it would only do necessary computing while you iterating through the sequence. 8 | 9 | ## Installation and usage 10 | The code is written is ES6 and transpiled into different format so you can easily integrate it into your project. 11 | 12 | * `src/linq.js`: Source code written in ES6. You could choose to use this file directly. 13 | * `linq.js`: Transpiled with Babel runtime mode. Use in server side or in browser with proper module loader. 14 | * `linq-browser.js`: Transpiled with Babel. Use in browser with `browser-polyfill.js`. 15 | 16 | 17 | **Details are explained below:** 18 | 19 | 20 | ### Use in Node.js 21 | 22 | * Install with `npm` 23 | ```bash 24 | npm install lazy-linq 25 | ``` 26 | 27 | * `require` and use it 28 | ```js 29 | var linq = require('lazy-linq'); 30 | 31 | var data = linq.asEnumerable([1, 2, 3]); 32 | data.select(function(x) { return x * 2}).forEach(function(x) { console.log(x); }); 33 | // output will be: 34 | // 2 35 | // 4 36 | // 6 37 | ``` 38 | 39 | ### Use in browsers without any loader 40 | 41 | * Install with `bower` 42 | ```bash 43 | bower install lazy-linq 44 | ``` 45 | This would also auto install the dependency [babel-polyfill](https://github.com/nicksrandall/babel-polyfill). 46 | 47 | * Include `browser-polyfill.js` and 'linq-browser.js' to your `index.html`. 48 | ```html 49 | 50 | 51 | ``` 52 | 53 | * Use it in your js files 54 | ```js 55 | var data = linq.asEnumerable([1, 2, 3]); 56 | data.select(function(x) { return x * 2}).forEach(function(x) { console.log(x); }); 57 | // output will be: 58 | // 2 59 | // 4 60 | // 6 61 | ``` 62 | 63 | ### Use in browsers when you're already using ES6 64 | 65 | You should use the linq code written in ES6 rather than the transpiled one and feed it to your ES6 transpiling engine along with all your other js files. 66 | 67 | * suggest to copy the source file to 'local' location first. This could avoid many problems... 68 | ```js 69 | gulp.src('node_modules/lazy-linq/src/linq.js') 70 | .pipe(gulp.dest('src/app/components/linq/')); 71 | ``` 72 | 73 | * `import` it in your `index.js` 74 | ```js 75 | // assuming index.js is in 'src/app/' folder 76 | import * as linq from 'components/linq/linq'; 77 | 78 | // then you could attach 'linq' to global namespace for convenience: 79 | this.linq = linq; 80 | 81 | // or any other way suiting your code. E.g. in `angular`: 82 | angular.module('myModule').constant('linq', linq); // make 'linq' be injectable in controller/service/etc. 83 | ``` 84 | 85 | #### Using `webpack` and [babel-loader](https://github.com/babel/babel-loader) (with `runtime` option) 86 | 87 | * Simply `import` the transpiled linq.js in you `index.js` 88 | ```js 89 | // assuming index.js is in 'src/app/' folder 90 | import * as linq from '../../node_components/lazy-linq/linq'; 91 | ``` 92 | That's it. `webpack` should be able to check dependencies and pack linq.js and babel runtime together into your packed index.js. 93 | 94 | 95 | ## Tutorial 96 | 97 | ### Basic usages 98 | ```js 99 | // create a lazy range of 1 ~ 100000 100 | var seq = linq.range(1, 100000); 101 | 102 | // create a enumerable object which WILL but NOT YET find all even numbers in seq 103 | var even = seq.where(function(x) { return x % 2 === 0; }); 104 | 105 | // find the first 100 even number. 106 | var count = 0; 107 | even.forEach(function(x) { 108 | console.log(x); 109 | if (++count >= 100) return; 110 | }); 111 | 112 | // use "even" again will cause it to be evaluated from start. 113 | // also find the first 100 even numbers and put them to an actual array. 114 | var top100_even = even.take(100).toArray(); 115 | ``` 116 | ### Helper functions 117 | ```js 118 | // generate a lazy sequence of [0, ... , 9] 119 | var seq = linq.range(0, 10); 120 | 121 | // generate a lazy sequence of [1, 1, 1, 1, 1] 122 | var seq = linq.repeat(1, 5); 123 | 124 | // generate a lazy empty sequence 125 | var seq = linq.empty(); 126 | 127 | ``` 128 | 129 | ### Use suffix form of `asEnumerable()` 130 | ```js 131 | // this will install asEnumerable() for `Array` and `String` 132 | linq.installAsEnumerable(); 133 | // then you can do this 134 | [1, 2, 3].asEnumerable().where(....) 135 | 136 | 137 | // if you have a custom class with iterator 138 | class MyCollection { 139 | [Symbol.iterator]: function* () { ... } 140 | } 141 | // you could also install asEnumerable() for it 142 | linq.installAsEnumerable(MyCollection); 143 | ``` 144 | 145 | ## Documentation 146 | 147 | Coming soon... 148 | -------------------------------------------------------------------------------- /src/spec/mergeSort.spec.js: -------------------------------------------------------------------------------- 1 | import { 2 | _mergeSortTestPack as algo 3 | } 4 | from '../linq'; 5 | 6 | function iterToArray(iter) { 7 | let elem; 8 | let result = []; 9 | while (!(elem = iter.next()).done) { 10 | result.push(elem.value); 11 | } 12 | return result; 13 | } 14 | 15 | describe('sort algo -> ', function () { 16 | describe('genSubSequences()', function () { 17 | 18 | it('should divided sequence by natural order', function () { 19 | let data = [2, 1, 3, 6, 4, 2, 2, 5, 3, 4]; 20 | let result = iterToArray(algo.genSubSequences(data, (x, y) => x - y, x => x <= 0)); 21 | expect(result).toEqual([ 22 | [2], 23 | [1, 3, 6], 24 | [4], 25 | [2, 2, 5], 26 | [3, 4] 27 | ]); 28 | }); 29 | 30 | it('should divide according to @comp', function () { 31 | let data = [2, 1, 3, 6, 4, 2, 2, 5, 3, 4]; 32 | let result = iterToArray(algo.genSubSequences(data, (x, y) => y - x, x => x <= 0)); 33 | expect(result).toEqual([ 34 | [2, 1], 35 | [3], 36 | [6, 4, 2, 2], 37 | [5, 3], 38 | [4] 39 | ]); 40 | }); 41 | 42 | it('should divide according to @compGroupChecker', function () { 43 | let data = [2, 1, 3, 6, 4, 2, 2, 5, 3, 4]; 44 | let result = iterToArray(algo.genSubSequences(data, (x, y) => x - y, x => x === 0)); 45 | expect(result).toEqual([ 46 | [2], 47 | [1], 48 | [3], 49 | [6], 50 | [4], 51 | [2, 2], 52 | [5], 53 | [3], 54 | [4] 55 | ]); 56 | }); 57 | 58 | it('when seqence is empty, should return empty sequence', function () { 59 | let data = []; 60 | let result = iterToArray(algo.genSubSequences(data, (x, y) => x - y, x => x <= 0)); 61 | expect(result.length).toBe(0); 62 | }); 63 | 64 | it('should divide undefined separately', function () { 65 | let data = [2, 1, 3, undefined, 6, 4, 2, 2, 5, 3, 4]; 66 | let result = iterToArray(algo.genSubSequences(data, (x, y) => x - y, x => x <= 0)); 67 | expect(result).toEqual([ 68 | [2], 69 | [1, 3], 70 | [undefined], 71 | [6], 72 | [4], 73 | [2, 2, 5], 74 | [3, 4] 75 | ]); 76 | }); 77 | 78 | it('should divide multiple undefined separately', function () { 79 | let data = [2, 1, 3, undefined, undefined, 6, 4, 2, 2, 5, 3, 4]; 80 | let result = iterToArray(algo.genSubSequences(data, (x, y) => x - y, x => x <= 0)); 81 | expect(result).toEqual([ 82 | [2], 83 | [1, 3], 84 | [undefined], 85 | [undefined], 86 | [6], 87 | [4], 88 | [2, 2, 5], 89 | [3, 4] 90 | ]); 91 | }); 92 | 93 | it('should divide invalid value separately', function () { 94 | let data = [2, 1, 3, null, 'abc', 6, 4, 2, 2, 5, 3, 4]; 95 | let result = iterToArray(algo.genSubSequences(data, (x, y) => x - y, x => x <= 0)); 96 | expect(result).toEqual([ 97 | [2], 98 | [1, 3], 99 | [null], 100 | ['abc'], 101 | [6], 102 | [4], 103 | [2, 2, 5], 104 | [3, 4] 105 | ]); 106 | }); 107 | }); 108 | 109 | describe('genTwoMergedSequence()', function () { 110 | it('should merge', function () { 111 | let data1 = [1, 3, 4]; 112 | let data2 = [2, 4, 5]; 113 | let result = iterToArray(algo.genTwoMergedSequence(data1, data2, (x, y) => x - y)); 114 | expect(result).toEqual([1, 2, 3, 4, 4, 5]); 115 | }); 116 | 117 | it('should merge according to @comp', function () { 118 | let data1 = [4, 3, 1]; 119 | let data2 = [5, 4, 2]; 120 | let result = iterToArray(algo.genTwoMergedSequence(data1, data2, (x, y) => y - x)); 121 | expect(result).toEqual([5, 4, 4, 3, 2, 1]); 122 | }); 123 | 124 | it('should workd fine when one sequence is empty', function () { 125 | let data1 = [1, 3, 4]; 126 | let data2 = [2, 4, 5]; 127 | 128 | var result = iterToArray(algo.genTwoMergedSequence([], data2, (x, y) => x - y)); 129 | expect(result).toEqual([2, 4, 5]); 130 | 131 | var result = iterToArray(algo.genTwoMergedSequence(data1, [], (x, y) => x - y)); 132 | expect(result).toEqual([1, 3, 4]); 133 | }); 134 | 135 | it('should merge undefined alone', function () { 136 | let data1 = [1, 3, 4]; 137 | let data2 = [undefined]; 138 | // let data3 = [2, 5]; 139 | let result = iterToArray(algo.genTwoMergedSequence(data1, data2, (x, y) => x - y)); 140 | expect(result).toEqual([undefined, 1, 3, 4]); // the position of 'undefined' is not important 141 | }); 142 | 143 | it('should merge undefined mixed', function () { 144 | let data1 = [2, 4, undefined]; 145 | let data2 = [1, 3]; 146 | // let data3 = [2, 5]; 147 | let result = iterToArray(algo.genTwoMergedSequence(data1, data2, (x, y) => x - y)); 148 | expect(result).toEqual([1, 2, 3, 4, undefined ]); // the position of 'undefined' is not important 149 | }); 150 | 151 | it('should merge undefined mixed in middle', function () { 152 | let data1 = [2, undefined, 4]; 153 | let data2 = [1, 3]; 154 | // let data3 = [2, 5]; 155 | let result = iterToArray(algo.genTwoMergedSequence(data1, data2, (x, y) => x - y)); 156 | expect(result).toEqual([1, 2, undefined, 3, 4 ]); // the position of 'undefined' is not important 157 | }); 158 | 159 | it('should merge undefined in head of array', function () { 160 | let data1 = [undefined, 1]; 161 | let data2 = [1, 3]; 162 | let result = iterToArray(algo.genTwoMergedSequence(data1, data2, (x, y) => x - y)); 163 | expect(result).toEqual([undefined, 1, 1, 3]); // the position of 'undefined' is not important 164 | }); 165 | }); 166 | 167 | describe('genMergedAndSortedSequence()', function () { 168 | it('when sequence count is even, should merge correctly', function () { 169 | let data = [[1, 2], [1, 4], [2], [1, 3]]; 170 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 171 | 172 | expect(result).toEqual([1, 1, 1, 2, 2, 3, 4]); 173 | }); 174 | 175 | it('when sequence count is odd, should merge correctly', function () { 176 | let data = [[1, 2], [1, 4], [2]]; 177 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 178 | 179 | expect(result).toEqual([1, 1, 2, 2, 4]); 180 | }); 181 | 182 | it('when sequence count is 2, should merge correctly', function () { 183 | let data = [[1, 2], [1, 4]]; 184 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 185 | 186 | expect(result).toEqual([1, 1, 2, 4]); 187 | }); 188 | 189 | 190 | it('when sequence count is 1, should return it directly', function () { 191 | let data = [[1, 2]]; 192 | 193 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 194 | 195 | expect(result).toEqual([1, 2]); 196 | }); 197 | 198 | it('when sequence count is 0, should return empty sequence', function () { 199 | let data = []; 200 | 201 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 202 | 203 | expect(result.length).toEqual(0); 204 | }); 205 | 206 | it('when some sequence is empty, should merge without error', function () { 207 | let data = [[1, 2], [1, 4], [], []]; 208 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 209 | 210 | expect(result).toEqual([1, 1, 2, 4]); 211 | }); 212 | 213 | it('when sequence has undefined, should merge correctly', function () { 214 | let data = [[1, 2], [undefined], [1, 3]]; 215 | let result = iterToArray(algo.genMergedAndSortedSequence(data[Symbol.iterator](), (x, y) => x - y)); 216 | 217 | expect(result).toEqual([undefined, 1, 1, 2, 3]); 218 | }); 219 | }); 220 | 221 | describe('genMergeSort()', function () { 222 | it('should sort correctly', function () { 223 | let data = [3, 2, 7, 9, 5, 0]; 224 | let result = iterToArray(algo.genMergeSort(data, (x, y) => x - y)); 225 | 226 | expect(result).toEqual([0, 2, 3, 5, 7, 9]); 227 | }); 228 | 229 | it('when sequence is empty, should return empty sequence', function () { 230 | let data = []; 231 | let result = iterToArray(algo.genMergeSort(data, (x, y) => x - y)); 232 | 233 | expect(result.length).toBe(0); 234 | }); 235 | 236 | it('when sequence contains only 1 element, should work fine', function () { 237 | let data = [3]; 238 | let result = iterToArray(algo.genMergeSort(data, (x, y) => x - y)); 239 | 240 | expect(result).toEqual([3]); 241 | }); 242 | 243 | it('when sequence contains only 2 elements, should work fine', function () { 244 | let data = [6, 2]; 245 | let result = iterToArray(algo.genMergeSort(data, (x, y) => x - y)); 246 | 247 | expect(result).toEqual([2, 6]); 248 | }); 249 | 250 | it('when @comp is provided, should sort by it', function () { 251 | let data = [1, 3, 2]; 252 | let result = iterToArray(algo.genMergeSort(data, (x, y) => y - x)); 253 | 254 | expect(result).toEqual([3, 2, 1]); 255 | }); 256 | 257 | it('should be stable', function () { 258 | let data = ['bd', 'bb', 'cc', 'aa', 'ab']; 259 | let result = iterToArray(algo.genMergeSort(data, (x, y) => x[0] < y[0] ? -1 : (x[0] === y[0] ? 0 : 1))); 260 | 261 | expect(result).toEqual(['aa', 'ab', 'bd', 'bb', 'cc']); 262 | }); 263 | 264 | it('should sort correctly with undefined', function () { 265 | let data = [3, 2, 7, 9, undefined, 5, 0]; 266 | let result = iterToArray(algo.genMergeSort(data, (x, y) => x - y)); 267 | 268 | expect(result).toEqual([undefined, 0, 2, 3, 5, 7, 9]); 269 | }); 270 | }); 271 | 272 | }); 273 | -------------------------------------------------------------------------------- /src/spec/linq.chain.spec.js: -------------------------------------------------------------------------------- 1 | import * as linq from '../linq'; 2 | 3 | linq.installAsEnumerable(); 4 | 5 | describe('linq lib -> chain members ->', function () { 6 | describe('skip()', function () { 7 | let data = linq.range(1, 3); 8 | 9 | it('when @n is not an integer, should throw', function () { 10 | expect(() => data.skip()).toThrow(); 11 | expect(() => data.skip(null)).toThrow(); 12 | expect(() => data.skip({})).toThrow(); 13 | expect(() => data.skip(1.2)).toThrow(); 14 | }); 15 | 16 | it('when @n <= 0, should skip none', function () { 17 | expect(data.skip(0).toArray()).toEqual([1, 2, 3]); 18 | expect(data.skip(-1).toArray()).toEqual([1, 2, 3]); 19 | }); 20 | 21 | it('when @n > 0, should skip @n', function () { 22 | expect(data.skip(1).toArray()).toEqual([2, 3]); 23 | }); 24 | }); 25 | 26 | describe('skipWhile()', function () { 27 | let data = linq.range(1, 3); 28 | 29 | it('when @pred is not a function, should throw', function () { 30 | expect(() => data.skipWhile().toArray()).toThrow(); 31 | expect(() => data.skipWhile(1).toArray()).toThrow(); 32 | expect(() => data.skipWhile({}).toArray()).toThrow(); 33 | }); 34 | 35 | it('should skip while @pred() is true', function () { 36 | expect(data.skipWhile(x => x <= 2).toArray()).toEqual([3]); 37 | }); 38 | }); 39 | 40 | describe('take()', function () { 41 | let data = linq.range(1, 3); 42 | 43 | it('when @n is not an integer, should throw', function () { 44 | expect(() => data.take()).toThrow(); 45 | expect(() => data.take(null)).toThrow(); 46 | expect(() => data.take({})).toThrow(); 47 | expect(() => data.take(1.2)).toThrow(); 48 | }); 49 | 50 | it('when @n <= 0, should take none', function () { 51 | expect(data.take(0).toArray().length).toEqual(0); 52 | expect(data.take(-1).toArray().length).toEqual(0); 53 | }); 54 | 55 | it('when @n > 0, should take @n', function () { 56 | expect(data.take(2).toArray()).toEqual([1, 2]); 57 | }); 58 | }); 59 | 60 | describe('takeWhile()', function () { 61 | let data = linq.range(1, 3); 62 | 63 | it('when @pred is not a function, should throw', function () { 64 | expect(() => data.takeWhile().toArray()).toThrow(); 65 | }); 66 | 67 | it('should take while @pred() is true', function () { 68 | expect(data.takeWhile(x => x <= 2).toArray()).toEqual([1, 2]); 69 | }); 70 | }); 71 | 72 | describe('reverse()', function () { 73 | let data = linq.range(1, 3); 74 | 75 | it('when sequence is not empty, should reverse() all elements', function () { 76 | expect(data.reverse().toArray()).toEqual([3, 2, 1]); 77 | }); 78 | 79 | it('when sequence is empty, should return empty sequence', function () { 80 | expect(linq.empty().reverse().toArray().length).toBe(0); 81 | }); 82 | }); 83 | 84 | describe('select()', function () { 85 | let data = linq.range(1, 3); 86 | 87 | it('when @trans is not a function, should throw', function () { 88 | expect(() => data.select()).toThrow(); 89 | expect(() => data.select(1)).toThrow(); 90 | expect(() => data.select({})).toThrow(); 91 | }); 92 | 93 | it('should transform values', function () { 94 | expect(data.select(x => x + 1).toArray()).toEqual([2, 3, 4]); 95 | }); 96 | }); 97 | 98 | describe('where()', function () { 99 | let data = linq.range(1, 3); 100 | 101 | it('when @pred is not a funtion, should throw', function () { 102 | expect(() => data.where().toArray()).toThrow(); 103 | expect(() => data.where(1).toArray()).toThrow(); 104 | expect(() => data.where({}).toArray()).toThrow(); 105 | }); 106 | 107 | it('should return all element meet @pred', function () { 108 | expect(data.where(x => x % 2 !== 0).toArray()).toEqual([1, 3]); 109 | }); 110 | }); 111 | 112 | describe('selectMany()', function () { 113 | let data = linq.range(1, 3); 114 | 115 | it('when @genSeq is not a function, should throw', function () { 116 | expect(() => data.selectMany().toArray()).toThrow(); 117 | expect(() => data.selectMany(1).toArray()).toThrow(); 118 | expect(() => data.selectMany({}).toArray()).toThrow(); 119 | }); 120 | 121 | it('when @resultTrans is not provided, should flat all result of @genSeq', function () { 122 | expect(data.selectMany(x => linq.repeat(x, 2)).toArray()).toEqual([1, 1, 2, 2, 3, 3]); 123 | }); 124 | 125 | it('when @resultTrans is provided, should transform each result of @genSeq', function () { 126 | expect(data.selectMany(x => linq.repeat(x, 2), (x, seq) => seq.sum()).toArray()).toEqual([2, 4, 6]); 127 | }); 128 | }); 129 | 130 | describe('groupBy()', function () { 131 | let data = [1, 2, 3, 1].asEnumerable(); 132 | 133 | it('when all parameters are default, should use element themselves as key and value', function () { 134 | let result = data.groupBy().toArray(); 135 | expect(result.length).toBe(3); 136 | expect(result[0].key).toEqual(1); 137 | expect(result[0].toArray()).toEqual([1, 1]); 138 | expect(result[1].key).toEqual(2); 139 | expect(result[1].toArray()).toEqual([2]); 140 | expect(result[2].key).toEqual(3); 141 | expect(result[2].toArray()).toEqual([3]); 142 | }); 143 | 144 | it('when @keySelector is custom, should use @keySelector(element) as key', function () { 145 | let result = data.groupBy(x => x % 2).toArray(); 146 | expect(result.length).toBe(2); 147 | expect(result[0].key).toEqual(1); 148 | expect(result[0].toArray()).toEqual([1, 3, 1]); 149 | expect(result[1].key).toEqual(0); 150 | expect(result[1].toArray()).toEqual([2]); 151 | }); 152 | 153 | it('when @valueSelector is custom, should use @valueSelector(element) as value', function () { 154 | let result = data.groupBy(x => x, y => y * -1).toArray(); 155 | expect(result.length).toBe(3); 156 | expect(result[0].key).toEqual(1); 157 | expect(result[0].toArray()).toEqual([-1, -1]); 158 | expect(result[1].key).toEqual(2); 159 | expect(result[1].toArray()).toEqual([-2]); 160 | expect(result[2].key).toEqual(3); 161 | expect(result[2].toArray()).toEqual([-3]); 162 | }); 163 | 164 | it('when @resultTrans is custom, should use @resultTrans(key, valSeq) as final value', function () { 165 | let result = data.groupBy(x => x, y => y, (key, valSeq) => valSeq.asEnumerable().sum()).toArray(); 166 | expect(result.length).toBe(3); 167 | expect(result[0]).toEqual(2); 168 | expect(result[1]).toEqual(2); 169 | expect(result[2]).toEqual(3); 170 | }); 171 | 172 | it('when @keyEqual is custom, should use it to determine whether two keys are equal or not', function () { 173 | let data = ['ab', 'bc', 'aa', 'cc'].asEnumerable(); 174 | let result = data.groupBy(...[, , , (x, y) => x[0] === y[0]]).toArray(); 175 | expect(result.length).toBe(3); 176 | expect(result[0].key).toEqual('ab'); 177 | expect(result[0].toArray()).toEqual(['ab', 'aa']); 178 | expect(result[1].key).toEqual('bc'); 179 | expect(result[1].toArray()).toEqual(['bc']); 180 | expect(result[2].key).toEqual('cc'); 181 | expect(result[2].toArray()).toEqual(['cc']); 182 | }); 183 | }); 184 | 185 | describe('orderBy()', function () { 186 | let data = [3, 1, 2].asEnumerable(); 187 | 188 | it('should sort correctly', function () { 189 | expect(data.orderBy().toArray()).toEqual([1, 2, 3]); 190 | }); 191 | 192 | it('when @keySelector is custom, should order by @keySelector(element)', function () { 193 | expect(data.orderBy(x => 1 / x).toArray()).toEqual([3, 2, 1]); 194 | }); 195 | 196 | it('when @comp is custom, should compare elements pair by @comp(elem1, elem2)', function () { 197 | expect(data.orderBy(x => x, (x, y) => y - x).toArray()).toEqual([3, 2, 1]); 198 | }); 199 | 200 | it('should be stable', function () { 201 | let data = ['ba', 'cb', 'ab', 'ca', 'aa', 'bb'].asEnumerable(); 202 | 203 | expect(data.orderBy(x => x[0]).toArray()).toEqual(['ab', 'aa', 'ba', 'bb', 'cb', 'ca']); 204 | }); 205 | }); 206 | 207 | describe('thenBy()', function () { 208 | let data = ['cac', 'bca', 'cba', 'cab'].asEnumerable(); 209 | 210 | it('should sort after orderBy()', function () { 211 | expect(data.orderBy(x => x[0]).thenBy(x => x[1]).toArray()).toEqual(['bca', 'cac', 'cab', 'cba']); 212 | }); 213 | 214 | it('should sort for more than one thenBy()', function () { 215 | expect(data.orderBy(x => x[0]).thenBy(x => x[1]).thenBy(x => x[2]).toArray()).toEqual(['bca', 'cab', 'cac', 'cba']); 216 | }); 217 | 218 | it('duplicated key selector to should not change order', function () { 219 | expect(data.orderBy(x => x[0]).thenBy(x => x[0]).thenBy(x => x[0]).toArray()).toEqual(['bca', 'cac', 'cba', 'cab']); 220 | }); 221 | 222 | it('when not follow a orderBy(), should throw', function () { 223 | expect(() => data.thenBy(x => x)).toThrow(); 224 | }); 225 | 226 | it('when @keySelector is default, should use whole value to sort', function () { 227 | expect(data.orderBy(x => x[0]).thenBy().toArray()).toEqual(['bca', 'cab', 'cac', 'cba']); 228 | }); 229 | 230 | it('when @comp is custom, should use it to sort', function () { 231 | let comp = (x, y) => x === y ? 0 : (x < y ? 1 : -1); 232 | expect(data.orderBy(x => x[0]).thenBy(x => x[1], comp).toArray()).toEqual(['bca', 'cba', 'cac', 'cab']); 233 | }); 234 | }); 235 | 236 | describe('orderByDescending()', function () { 237 | let data = [3, 1, 2].asEnumerable(); 238 | 239 | it('should sort dec', function () { 240 | expect(data.orderByDescending().toArray()).toEqual([3, 2, 1]); 241 | }); 242 | }); 243 | 244 | describe('thenByDescending()', function () { 245 | let data = ['cac', 'bca', 'cba', 'cab'].asEnumerable(); 246 | 247 | it('should sort after orderBy() desc', function () { 248 | expect(data.orderBy(x => x[0]).thenByDescending(x => x[1]).toArray()).toEqual(['bca', 'cba', 'cac', 'cab']); 249 | }); 250 | 251 | it('should work with orderByDescending()', function () { 252 | expect(data.orderByDescending(x => x[0]).thenByDescending(x => x[1]).toArray()).toEqual(['cba', 'cac', 'cab', 'bca']); 253 | }); 254 | }); 255 | 256 | describe('join()', function () { 257 | let data1 = [1, 2, 3, 4].asEnumerable(); 258 | let data2 = [2, 4, 6]; 259 | 260 | it('when other is not provided, should throw', function () { 261 | expect(() => data1.join()).toThrow(); 262 | expect(() => data1.join(null)).toThrow(); 263 | }); 264 | 265 | it('with default parameters, should join by values them selves and return a sequence of array with both values from left and right sequences', function () { 266 | expect(data1.join(data2).toArray()).toEqual([ 267 | [2, 2], 268 | [4, 4] 269 | ]); 270 | }); 271 | 272 | it('when no pair matched, should return empty result', function () { 273 | expect(data1.join([5, 6]).toArray().length).toBe(0); 274 | }); 275 | 276 | it('when any or both sequences are empty, should return empty result', function () { 277 | expect(data1.join([]).toArray().length).toBe(0); 278 | expect([].asEnumerable().join(data2).toArray().length).toBe(0); 279 | expect([].asEnumerable().join([]).toArray().length).toBe(0); 280 | }); 281 | 282 | it('when @thisKeySelector is provided, should use it', function () { 283 | expect(data1.join(data2, x => x + 1).toArray()).toEqual([ 284 | [1, 2], 285 | [3, 4] 286 | ]); 287 | }); 288 | 289 | it('when @otherKeySelector is provided, should use it', function () { 290 | expect(data1.join(data2, undefined, y => y - 1).toArray()).toEqual([ 291 | [1, 2], 292 | [3, 4] 293 | ]); 294 | }); 295 | 296 | it('when @resultTrans is provided, should use it', function () { 297 | expect(data1.join(data2, ...[, , (x, y) => x + y]).toArray()).toEqual([4, 8]); 298 | }); 299 | 300 | it('when @equal is provided, should use it', function () { 301 | expect(data1.join(data2, ...[, , , (x, y) => x + 1 === y]).toArray()).toEqual([ 302 | [1, 2], 303 | [3, 4] 304 | ]); 305 | }); 306 | }); 307 | 308 | describe('groupJoin()', function () { 309 | let data1 = [1, 2, 3, 4].asEnumerable(); 310 | let data2 = [2, 4, 6]; 311 | 312 | it('when other is not provided, should throw', function () { 313 | expect(() => data1.join()).toThrow(); 314 | expect(() => data1.join(null)).toThrow(); 315 | }); 316 | 317 | it('with default parameters, should join by values them selves and return a sequence of array with both values from left and right sequences', function () { 318 | expect(data1.join(data2).toArray()).toEqual([ 319 | [2, 2], 320 | [4, 4] 321 | ]); 322 | }); 323 | 324 | it('when no pair matched, should return empty result', function () { 325 | expect(data1.join([5, 6]).toArray().length).toBe(0); 326 | }); 327 | 328 | it('when any or both sequences are empty, should return empty result', function () { 329 | expect(data1.join([]).toArray().length).toBe(0); 330 | expect([].asEnumerable().join(data2).toArray().length).toBe(0); 331 | expect([].asEnumerable().join([]).toArray().length).toBe(0); 332 | }); 333 | 334 | it('when @thisKeySelector is provided, should use it', function () { 335 | expect(data1.join(data2, x => x + 1).toArray()).toEqual([ 336 | [1, 2], 337 | [3, 4] 338 | ]); 339 | }); 340 | 341 | it('when @otherKeySelector is provided, should use it', function () { 342 | expect(data1.join(data2, undefined, y => y - 1).toArray()).toEqual([ 343 | [1, 2], 344 | [3, 4] 345 | ]); 346 | }); 347 | 348 | it('when @resultTrans is provided, should use it', function () { 349 | expect(data1.join(data2, ...[, , (x, y) => x + y]).toArray()).toEqual([4, 8]); 350 | }); 351 | 352 | it('when @equal is provided, should use it', function () { 353 | expect(data1.join(data2, ...[, , , (x, y) => x + 1 === y]).toArray()).toEqual([ 354 | [1, 2], 355 | [3, 4] 356 | ]); 357 | }); 358 | }); 359 | 360 | describe('zip()', function () { 361 | let data1 = [1, 2].asEnumerable(); 362 | let data2 = [2, 3, 4]; 363 | 364 | it('when @other is not provided, should throw', function () { 365 | expect(() => data1.zip()).toThrow(); 366 | expect(() => data1.zip(null)).toThrow(); 367 | }); 368 | 369 | it('when all parameter are default, should generate matched pair array', function () { 370 | expect(data1.zip(data2).toArray()).toEqual([ 371 | [1, 2], 372 | [2, 3] 373 | ]) 374 | }); 375 | 376 | it('when one of or both sequences are empty, should return empty sequence', function () { 377 | expect(data1.zip([]).toArray()).toEqual([]); 378 | expect([].asEnumerable().zip(data2).toArray()).toEqual([]); 379 | expect([].asEnumerable().zip([]).toArray()).toEqual([]); 380 | }); 381 | }); 382 | 383 | describe('concat()', function () { 384 | let data1 = [1, 2].asEnumerable(); 385 | let data2 = [2, 3]; 386 | 387 | it('when @other is not provided, should throw', function () { 388 | expect(() => data1.concat()).toThrow(); 389 | expect(() => data1.concat(null)).toThrow(); 390 | }); 391 | 392 | it('should concat both sequences', function () { 393 | expect(data1.concat(data2).toArray()).toEqual([1, 2, 2, 3]); 394 | }); 395 | 396 | it('when either or both of the two sequences are empty, should work fine', function () { 397 | expect(data1.concat([]).toArray()).toEqual([1, 2]); 398 | expect([].asEnumerable().concat(data2).toArray()).toEqual([2, 3]); 399 | expect([].asEnumerable().concat([]).toArray()).toEqual([]); 400 | }); 401 | }); 402 | 403 | describe('otherThan()', function () { 404 | let data1 = [1, 2, 1].asEnumerable(); 405 | let data2 = [2, 3, 2]; 406 | 407 | it('when @other is not provided, should throw', function () { 408 | expect(() => data1.otherThan()).toThrow(); 409 | expect(() => data1.otherThan(null)).toThrow(); 410 | }); 411 | 412 | it('should remove items from this who are equal to any iterm in other', function () { 413 | expect(data1.otherThan(data2).toArray()).toEqual([1, 1]); 414 | }); 415 | 416 | it('when @other is an empty sequence, should return this sequence', function () { 417 | expect(data1.otherThan([]).toArray()).toEqual([1, 2, 1]); 418 | }); 419 | 420 | it('when this is an empty sequence, should return empty sequence', function () { 421 | expect([].asEnumerable().otherThan(data2).toArray()).toEqual([]); 422 | }); 423 | 424 | it('when @equal is provided, should use it to compare items', function () { 425 | data1 = ['ab', 'bb'].asEnumerable(); 426 | data2 = ['ac', 'aa']; 427 | expect(data1.otherThan(data2, (x, y) => x[0] === y[0]).toArray()).toEqual(['bb']); 428 | }); 429 | }); 430 | 431 | describe('distinct()', function () { 432 | let data = [1, 2, 3, 2, 1].asEnumerable(); 433 | 434 | it('when @equal is default, should remove duplicated items', function () { 435 | expect(data.distinct().toArray()).toEqual([1, 2, 3]); 436 | }); 437 | 438 | it('when @equal is custom, should use it to compare items', function () { 439 | data = ['ab', 'bb', 'ac'].asEnumerable(); 440 | expect(data.distinct((x, y) => x[0] == y[0]).toArray()).toEqual(['ab', 'bb']); 441 | }); 442 | 443 | it('when this is empty, should return empty', function () { 444 | expect([].asEnumerable().distinct().toArray()).toEqual([]); 445 | }); 446 | }); 447 | 448 | describe('union()', function () { 449 | let data1 = [1, 2, 1].asEnumerable(); 450 | let data2 = [2, 3, 2]; 451 | 452 | it('when @other is not provided, should throw', function () { 453 | expect(() => data1.union()).toThrow(); 454 | expect(() => data1.union(null)).toThrow(); 455 | }); 456 | 457 | it('should contain items from both sequnces with no duplication', function () { 458 | expect(data1.union(data2).toArray()).toEqual([1, 2, 3]); 459 | }); 460 | 461 | it('when @other is an empty sequence, should return this sequence with no duplication', function () { 462 | expect(data1.union([]).toArray()).toEqual([1, 2]); 463 | }); 464 | 465 | it('when this is an empty sequence, should other sequence', function () { 466 | expect([].asEnumerable().union(data2).toArray()).toEqual([2, 3]); 467 | }); 468 | 469 | it('when @equal is provided, should use it to compare items', function () { 470 | data1 = ['ab', 'bb'].asEnumerable(); 471 | data2 = ['ac', 'aa']; 472 | expect(data1.union(data2, (x, y) => x[0] === y[0]).toArray()).toEqual(['ab', 'bb']); 473 | }); 474 | }); 475 | 476 | describe('intersect()', function () { 477 | let data1 = [1, 2, 1].asEnumerable(); 478 | let data2 = [2, 3, 2]; 479 | 480 | it('when @other is not provided, should throw', function () { 481 | expect(() => data1.intersect()).toThrow(); 482 | expect(() => data1.intersect(null)).toThrow(); 483 | }); 484 | 485 | it('should contain items exist in both sequnces but with no duplication', function () { 486 | expect(data1.intersect(data2).toArray()).toEqual([2]); 487 | }); 488 | 489 | it('when @other is an empty sequence, should return empty sequence', function () { 490 | expect(data1.intersect([]).toArray()).toEqual([]); 491 | }); 492 | 493 | it('when this is an empty sequence, should return empty sequence', function () { 494 | expect([].asEnumerable().intersect(data2).toArray()).toEqual([]); 495 | }); 496 | 497 | it('when @equal is provided, should use it to compare items', function () { 498 | data1 = ['ab', 'bb'].asEnumerable(); 499 | data2 = ['ac', 'aa']; 500 | expect(data1.intersect(data2, (x, y) => x[0] === y[0]).toArray()).toEqual(['ab']); 501 | }); 502 | }); 503 | 504 | describe('except()', function () { 505 | let data1 = [1, 2, 1].asEnumerable(); 506 | let data2 = [2, 3, 2]; 507 | 508 | it('when @other is not provided, should throw', function () { 509 | expect(() => data1.except()).toThrow(); 510 | expect(() => data1.except(null)).toThrow(); 511 | }); 512 | 513 | it('should remove items from this who are equal to any iterm in other and also remove any duplication in this', function () { 514 | expect(data1.except(data2).toArray()).toEqual([1]); 515 | }); 516 | 517 | it('when @other is an empty sequence, should return this sequence', function () { 518 | expect(data1.except([]).toArray()).toEqual([1, 2]); 519 | }); 520 | 521 | it('when this is an empty sequence, should return empty sequence', function () { 522 | expect([].asEnumerable().except(data2).toArray()).toEqual([]); 523 | }); 524 | 525 | it('when @equal is provided, should use it to compare items', function () { 526 | data1 = ['ab', 'bb', 'ad'].asEnumerable(); 527 | data2 = ['ac', 'aa']; 528 | expect(data1.except(data2, (x, y) => x[0] === y[0]).toArray()).toEqual(['bb']); 529 | }); 530 | }); 531 | }); 532 | -------------------------------------------------------------------------------- /src/spec/linq.eval.spec.js: -------------------------------------------------------------------------------- 1 | import * as linq from '../linq'; 2 | 3 | linq.installAsEnumerable(); 4 | 5 | describe('linq lib -> eval members ->', function () { 6 | describe('all()', function () { 7 | it('when @pred is not a function, should throw', function () { 8 | expect(() => data.all()).toThrow(); 9 | expect(() => data.all(1)).toThrow(); 10 | expect(() => data.all({})).toThrow(); 11 | }); 12 | 13 | let data = linq.range(1, 3); 14 | 15 | describe('with non-empty sequence', function () { 16 | it('when all are true, should return true', function () { 17 | expect(data.all(x => x > 0)).toBe(true); 18 | }); 19 | 20 | it('when all are false, should return false', function () { 21 | expect(data.all(x => x < 0)).toBe(false); 22 | }); 23 | 24 | it('when some are true and some are false, should return false', function () { 25 | expect(data.all(x => x > 1)).toBe(false); 26 | }); 27 | }); 28 | 29 | describe('with empty sequence', function () { 30 | it('should always return true', function () { 31 | expect(linq.empty().all(x => false)).toBe(true); 32 | }); 33 | }); 34 | }); 35 | 36 | 37 | describe('any()', function () { 38 | let data = linq.range(1, 3); 39 | 40 | describe('with non-empty sequence', function () { 41 | it('when all are true, should return true', function () { 42 | expect(data.any(x => x > 0)).toBe(true); 43 | }); 44 | 45 | it('when all are false, should return false', function () { 46 | expect(data.any(x => x < 0)).toBe(false); 47 | }); 48 | 49 | it('when some are true and some are false, should return false', function () { 50 | expect(data.any(x => x > 1)).toBe(true); 51 | }); 52 | 53 | it('when @pred is undefined, should return true', function () { 54 | expect(data.any()).toBe(true); 55 | }); 56 | }); 57 | 58 | describe('with empty sequence', function () { 59 | it('should always return false', function () { 60 | expect(linq.empty().any(x => true)).toBe(false); 61 | expect(linq.empty().any()).toBe(false); 62 | }); 63 | }); 64 | }); 65 | 66 | describe('singleOrDefault()', function () { 67 | describe('with empty sequence', function () { 68 | let data = linq.empty(); 69 | 70 | it('should always return undefined', function () { 71 | expect(data.singleOrDefault()).toBeUndefined(); 72 | expect(data.singleOrDefault(x => true)).toBeUndefined(); 73 | }); 74 | }); 75 | 76 | describe('with sequence with only one element', function () { 77 | let data = linq.range(1, 1); 78 | 79 | it('when @pred is default, should return the only element', function () { 80 | expect(data.singleOrDefault()).toBe(1); 81 | }); 82 | 83 | it('when @pred is custom and meet, should return the only element', function () { 84 | expect(data.singleOrDefault(x => x >= 1)).toBe(1); 85 | }); 86 | 87 | it('when @pred is custom and NOT meet, should return undefined', function () { 88 | expect(data.singleOrDefault(x => x >= 4)).toBeUndefined(); 89 | }); 90 | }); 91 | 92 | describe('with sequence with more than one element', function () { 93 | let data = linq.range(1, 3); 94 | 95 | it('when @pred is default, should throw', function () { 96 | expect(() => data.singleOrDefault()).toThrow(); 97 | }); 98 | 99 | it('when @pred is custom and meet once, should return the only meet element', function () { 100 | expect(data.singleOrDefault(x => x % 2 === 0)).toBe(2); 101 | }); 102 | 103 | it('when @pred is custom and meet twice, should throw', function () { 104 | expect(() => data.singleOrDefault(x => x % 2 !== 0)).toThrow(); 105 | }); 106 | 107 | it('when @pred is custom and NOT meet, should return undefined', function () { 108 | expect(data.singleOrDefault(x => x >= 4)).toBeUndefined(); 109 | }); 110 | }); 111 | }); 112 | 113 | describe('single()', function () { 114 | describe('with empty sequence', function () { 115 | let data = linq.empty(); 116 | 117 | it('should always throw', function () { 118 | expect(() => data.single()).toThrow(); 119 | expect(() => data.single(x => true)).toThrow(); 120 | }); 121 | }); 122 | 123 | describe('with sequence with only one element', function () { 124 | let data = linq.range(1, 1); 125 | 126 | it('when @pred is default, should return the only element', function () { 127 | expect(data.single()).toBe(1); 128 | }); 129 | 130 | it('when @pred is custom and meet, should return the only element', function () { 131 | expect(data.single(x => x >= 1)).toBe(1); 132 | }); 133 | 134 | it('when @pred is custom and NOT meet, should throw', function () { 135 | expect(() => data.single(x => x >= 4)).toThrow(); 136 | }); 137 | }); 138 | 139 | describe('with sequence with more than one element', function () { 140 | let data = linq.range(1, 3); 141 | 142 | it('when @pred is default, should throw', function () { 143 | expect(() => data.single()).toThrow(); 144 | }); 145 | 146 | it('when @pred is custom and meet once, should return the only meet element', function () { 147 | expect(data.single(x => x % 2 === 0)).toBe(2); 148 | }); 149 | 150 | it('when @pred is custom and meet twice, should throw', function () { 151 | expect(() => data.single(x => x % 2 !== 0)).toThrow(); 152 | }); 153 | 154 | it('when @pred is custom and NOT meet, should throw', function () { 155 | expect(() => data.single(x => x >= 4)).toThrow(); 156 | }); 157 | }); 158 | }); 159 | 160 | describe('count()', function () { 161 | let data = linq.range(1, 3); 162 | 163 | describe('with non-empty sequence', function () { 164 | it('when @pred != undefined should return matched count', function () { 165 | expect(data.count(x => x >= 2)).toBe(2); 166 | }); 167 | 168 | it('when @pred is undefined should return element count', function () { 169 | expect(data.count()).toBe(3); 170 | }); 171 | }); 172 | 173 | describe('with empty sequence', function () { 174 | it('should always return 0', function () { 175 | expect(linq.empty().count(x => true)).toBe(0); 176 | expect(linq.empty().count()).toBe(0); 177 | }); 178 | }); 179 | }); 180 | 181 | describe('contains()', function () { 182 | describe('with non-empty sequence', function () { 183 | describe('with default @comp', function () { 184 | let data = linq.range(1, 3); 185 | 186 | it('when @val is an existing element, should return true', function () { 187 | expect(data.contains(2)).toBe(true); 188 | }); 189 | 190 | it('when @val is NOT an existing element, should return false', function () { 191 | expect(data.contains(4)).toBe(false); 192 | }); 193 | }); 194 | 195 | describe('with custom @comp', function () { 196 | let data = ['aa', 'bb', 'cc'].asEnumerable(); 197 | 198 | it('when any @comp() result is true, should return true', function () { 199 | expect(data.contains('cd', (x, y) => x[0] === y[0])).toBe(true); 200 | }); 201 | 202 | it('when all @comp() result are false, should return false', function () { 203 | expect(data.contains('cd', (x, y) => x[1] === y[1])).toBe(false); 204 | }); 205 | }); 206 | }); 207 | 208 | describe('with empty sequence', function () { 209 | let data = linq.empty(); 210 | 211 | it('should always return false', function () { 212 | expect(data.contains(1)).toBe(false); 213 | expect(data.contains(1, (x, y) => true)).toBe(false); 214 | expect(data.contains()).toBe(false); 215 | }); 216 | }); 217 | }); 218 | 219 | describe('elementAtOrDefault()', function () { 220 | let data = linq.range(1, 3); 221 | let arrayData = [1, 2, 3].asEnumerable(); 222 | 223 | it('when @index is not an integer, should throw', function () { 224 | expect(() => linq.empty().elementAtOrDefault('abc')).toThrow(); 225 | expect(() => data.elementAtOrDefault('abc')).toThrow(); 226 | expect(() => linq.empty().elementAtOrDefault()).toThrow(); 227 | expect(() => data.elementAtOrDefault()).toThrow(); 228 | }); 229 | 230 | it('when @index is in range, should return the corresponding element', function () { 231 | expect(data.elementAtOrDefault(1)).toBe(2); 232 | expect(arrayData.elementAtOrDefault(1)).toBe(2); 233 | }); 234 | 235 | it('when @index is out of range, should return undefined', function () { 236 | expect(data.elementAtOrDefault(-1)).toBeUndefined(); 237 | expect(data.elementAtOrDefault(3)).toBeUndefined(); 238 | expect(arrayData.elementAtOrDefault(-1)).toBeUndefined(); 239 | expect(arrayData.elementAtOrDefault(3)).toBeUndefined(); 240 | }); 241 | }); 242 | 243 | describe('elementAt()', function () { 244 | let data = linq.range(1, 3); 245 | let arrayData = [1, 2, 3].asEnumerable(); 246 | 247 | it('when @index is not an integer, should throw', function () { 248 | expect(() => linq.empty().elementAt('abc')).toThrow(); 249 | expect(() => data.elementAt('abc')).toThrow(); 250 | expect(() => linq.empty().elementAt()).toThrow(); 251 | expect(() => data.elementAt()).toThrow(); 252 | }); 253 | 254 | it('when @index is in range, should return the corresponding element', function () { 255 | expect(data.elementAt(1)).toBe(2); 256 | expect(arrayData.elementAt(1)).toBe(2); 257 | }); 258 | 259 | it('when @index is out of range, should throw', function () { 260 | expect(() => data.elementAt(-1)).toThrow(); 261 | expect(() => data.elementAt(3)).toThrow(); 262 | expect(() => arrayData.elementAt(-1)).toThrow(); 263 | expect(() => arrayData.elementAt(3)).toThrow(); 264 | }); 265 | }); 266 | 267 | 268 | describe('firstOrDefault()', function () { 269 | describe('with non-empty sequence', function () { 270 | let data = linq.range(1, 3); 271 | 272 | it('when @pred is default, should return the first element', function () { 273 | expect(data.firstOrDefault()).toBe(1); 274 | }); 275 | 276 | it('when @pred is custom and meet, should return the first element that meets @pred', function () { 277 | expect(data.firstOrDefault(x => x >= 2)).toBe(2); 278 | }); 279 | 280 | it('when @pred is custom and NOT meet, should return undefined', function () { 281 | expect(data.firstOrDefault(x => x >= 4)).toBeUndefined(); 282 | }); 283 | }); 284 | 285 | describe('with empty sequence', function () { 286 | let data = linq.empty(); 287 | 288 | it('should always return undefined', function () { 289 | expect(data.firstOrDefault()).toBeUndefined(); 290 | expect(data.firstOrDefault(x => true)).toBeUndefined(); 291 | }); 292 | }); 293 | }); 294 | 295 | describe('first()', function () { 296 | describe('with non-empty sequence', function () { 297 | let data = linq.range(1, 3); 298 | 299 | it('when @pred is default, should return the first element', function () { 300 | expect(data.first()).toBe(1); 301 | }); 302 | 303 | it('when @pred is custom and meet, should return the first element that meets @pred', function () { 304 | expect(data.first(x => x >= 2)).toBe(2); 305 | }); 306 | 307 | it('when @pred is custom and NOT meet, should throw', function () { 308 | expect(() => data.first(x => x >= 4)).toThrow(); 309 | }); 310 | }); 311 | 312 | describe('with empty sequence', function () { 313 | let data = linq.empty(); 314 | 315 | it('should always throw', function () { 316 | expect(() => data.first()).toThrow(); 317 | expect(() => data.first(x => true)).toThrow(); 318 | }); 319 | }); 320 | }); 321 | 322 | describe('lastOrDefault()', function () { 323 | describe('with non-empty sequence', function () { 324 | let data = linq.range(1, 3); 325 | let arrayData = [1, 2, 3].asEnumerable(); 326 | 327 | it('when @pred is default, should return the last element', function () { 328 | expect(data.lastOrDefault()).toBe(3); 329 | expect(arrayData.lastOrDefault()).toBe(3); 330 | }); 331 | 332 | it('when @pred is custom and meet, should return the last element that meets @pred', function () { 333 | expect(data.lastOrDefault(x => x <= 2)).toBe(2); 334 | expect(arrayData.lastOrDefault(x => x <= 2)).toBe(2); 335 | }); 336 | 337 | it('when @pred is custom and NOT meet, should return undefined', function () { 338 | expect(data.lastOrDefault(x => x >= 4)).toBeUndefined(); 339 | expect(arrayData.lastOrDefault(x => x >= 4)).toBeUndefined(); 340 | }); 341 | }); 342 | 343 | describe('with empty sequence', function () { 344 | let data = linq.empty(); 345 | let arrayData = [].asEnumerable(); 346 | 347 | it('should always return undefined', function () { 348 | expect(data.lastOrDefault()).toBeUndefined(); 349 | expect(data.lastOrDefault(x => true)).toBeUndefined(); 350 | expect(arrayData.lastOrDefault()).toBeUndefined(); 351 | expect(arrayData.lastOrDefault(x => true)).toBeUndefined(); 352 | }); 353 | }); 354 | }); 355 | 356 | describe('last()', function () { 357 | describe('with non-empty sequence', function () { 358 | let data = linq.range(1, 3); 359 | let arrayData = [1, 2, 3].asEnumerable(); 360 | 361 | it('when @pred is default, should return the last element', function () { 362 | expect(data.last()).toBe(3); 363 | expect(arrayData.last()).toBe(3); 364 | }); 365 | 366 | it('when @pred is custom and meet, should return the last element that meets @pred', function () { 367 | expect(data.last(x => x <= 2)).toBe(2); 368 | expect(arrayData.last(x => x <= 2)).toBe(2); 369 | }); 370 | 371 | it('when @pred is custom and NOT meet, should throw', function () { 372 | expect(() => data.last(x => x >= 4)).toThrow(); 373 | expect(() => arrayData.last(x => x >= 4)).toThrow(); 374 | }); 375 | }); 376 | 377 | describe('with empty sequence', function () { 378 | let data = linq.empty(); 379 | let arrayData = [].asEnumerable(); 380 | 381 | it('should always throw', function () { 382 | expect(() => data.last()).toThrow(); 383 | expect(() => data.last(x => true)).toThrow(); 384 | expect(() => arrayData.last()).toThrow(); 385 | expect(() => arrayData.last(x => true)).toThrow(); 386 | }); 387 | }); 388 | }); 389 | 390 | describe('defaultIfEmpty()', function () { 391 | describe('with empty sequence', function () { 392 | it('when @val is defined, should return sequence contains only one element = @val', function () { 393 | expect(linq.empty().defaultIfEmpty(1).toArray()).toEqual([1]); 394 | }); 395 | 396 | it('when @val is undefined, should return an empty sequence', function () { 397 | expect(linq.empty().defaultIfEmpty().toArray().length).toBe(0); 398 | }); 399 | }); 400 | 401 | describe('with non-empty sequence', function () { 402 | let data = linq.range(1, 3); 403 | it('should always return original object', function () { 404 | expect(data.defaultIfEmpty()).toBe(data); 405 | }); 406 | }); 407 | }); 408 | 409 | describe('sequenceEqual()', function () { 410 | it('when two sequences are extatly equal, should return true', function () { 411 | let seq1 = linq.range(1, 3); 412 | let seq2 = linq.range(1, 3); 413 | expect(seq1.sequenceEqual(seq2)).toBe(true); 414 | }); 415 | 416 | it('when length are equal but elements are differnt, should return false', function () { 417 | let seq1 = linq.range(1, 3); 418 | let seq2 = linq.range(2, 3); 419 | expect(seq1.sequenceEqual(seq2)).toBe(false); 420 | }); 421 | 422 | it('when length are different, should return false', function () { 423 | let seq1 = linq.range(1, 3); 424 | let seq2 = linq.range(1, 4); 425 | expect(seq1.sequenceEqual(seq2)).toBe(false); 426 | }); 427 | }); 428 | 429 | describe('min()', function () { 430 | describe('with non-empty sequence', function () { 431 | let data = linq.range(1, 3); 432 | 433 | it('when @trans is default', function () { 434 | expect(data.min()).toBe(1); 435 | }); 436 | 437 | it('when @trans is custom, should return min defined by @trans result', function () { 438 | expect(data.min(x => x * -1)).toBe(-3); 439 | }); 440 | }); 441 | 442 | describe('with empty sequence', function () { 443 | let data = linq.empty(); 444 | 445 | it('always return undefined', function () { 446 | expect(data.min()).toBeUndefined(); 447 | expect(data.min(x => x * -1)).toBeUndefined(); 448 | }); 449 | }); 450 | }); 451 | 452 | describe('max()', function () { 453 | describe('with non-empty sequence', function () { 454 | let data = linq.range(1, 3); 455 | 456 | it('when @trans is default', function () { 457 | expect(data.max()).toBe(3); 458 | }); 459 | 460 | it('when @trans is custom, should return max defined by @trans result', function () { 461 | expect(data.max(x => x * -1)).toBe(-1); 462 | }); 463 | }); 464 | 465 | describe('with empty sequence', function () { 466 | let data = linq.empty(); 467 | 468 | it('always return undefined', function () { 469 | expect(data.max()).toBeUndefined(); 470 | expect(data.max(x => x * -1)).toBeUndefined(); 471 | }); 472 | }); 473 | }); 474 | 475 | describe('sum()', function () { 476 | describe('with non-empty sequence', function () { 477 | let data = linq.repeat(1, 3); 478 | 479 | it('when @trans is default', function () { 480 | expect(data.sum()).toBe(3); 481 | }); 482 | 483 | it('when @trans is custom, should return sum defined by @trans result', function () { 484 | expect(data.sum(x => x * -1)).toBe(-3); 485 | }); 486 | }); 487 | 488 | describe('with empty sequence', function () { 489 | let data = linq.empty(); 490 | 491 | it('always return 0', function () { 492 | expect(data.sum()).toBe(0); 493 | expect(data.sum(x => x * -1)).toBe(0); 494 | }); 495 | }); 496 | }); 497 | 498 | describe('average()', function () { 499 | describe('with non-empty sequence', function () { 500 | let data = linq.repeat(1, 3); 501 | 502 | it('when @trans is default', function () { 503 | expect(data.average()).toBe(1); 504 | }); 505 | 506 | it('when @trans is custom, should return sum defined by @trans result', function () { 507 | expect(data.average(x => x * -1)).toBe(-1); 508 | }); 509 | }); 510 | 511 | describe('with empty sequence', function () { 512 | let data = linq.empty(); 513 | 514 | it('always return 0', function () { 515 | expect(data.average()).toBe(0); 516 | expect(data.average(x => x * -1)).toBe(0); 517 | }); 518 | }); 519 | }); 520 | 521 | describe('aggregate()', function () { 522 | let data = linq.repeat(1, 3); 523 | 524 | it('when both @seed and @aggFunc are not provided, should throw', function () { 525 | expect(() => data.aggregate()).toThrow(); 526 | }); 527 | 528 | it('when @resultTrans is undefined, return the aggregate result directly', function () { 529 | expect(data.aggregate(1, (s, x) => s + x)).toBe(4); 530 | }); 531 | 532 | it('when @resultTrans defined, return the aggregate result transformed', function () { 533 | expect(data.aggregate(1, (s, x) => s + x, x => x * -1)).toBe(-4); 534 | }); 535 | 536 | describe('when only @seed is provided', function () { 537 | it('and sequence is empty, should return undefined', function () { 538 | expect(linq.empty().aggregate((s, x) => s + x)).toBeUndefined(); 539 | }); 540 | 541 | it('and sequence is not empty, should use the first element as seed', function () { 542 | expect(data.aggregate((s, x) => s + x)).toBe(3); 543 | }); 544 | }); 545 | }); 546 | 547 | describe('toArray()', function () { 548 | let data = linq.range(1, 3); 549 | 550 | it('should work', function () { 551 | expect(data.toArray()).toEqual([1, 2, 3]); 552 | }); 553 | }); 554 | 555 | describe('toSet()', function () { 556 | it('when sequence is empty, should return an empty Set', function () { 557 | let data = linq.empty(); 558 | expect(data.toSet().size).toBe(0); 559 | }); 560 | 561 | it('when sequence is not empty, should add all to Set', function () { 562 | let set = [1, 2, 2, 3].asEnumerable().toSet(); 563 | expect(set.size).toBe(3); 564 | expect(set.has(1)).toBe(true); 565 | expect(set.has(2)).toBe(true); 566 | expect(set.has(3)).toBe(true); 567 | }); 568 | }); 569 | 570 | describe('toMap()', function () { 571 | it('when sequence is empty, should always return empty Map', function () { 572 | let data = linq.empty(); 573 | expect(data.toMap().size).toBe(0); 574 | }); 575 | 576 | describe('testee name', function () { 577 | let data = ['aa', 'ab', 'bb', 'cc', 'bb'].asEnumerable(); 578 | 579 | it('should work with duplicated keys.', function () { 580 | let map = data.toMap(x => x, y => y[0]); 581 | expect(map.size).toBe(4); 582 | expect(map.has('aa')).toBe(true); 583 | expect(map.has('ab')).toBe(true); 584 | expect(map.has('bb')).toBe(true); 585 | expect(map.has('cc')).toBe(true); 586 | expect(map.get('aa')).toBe('a'); 587 | expect(map.get('ab')).toBe('a'); 588 | expect(map.get('bb')).toBe('b'); 589 | expect(map.get('cc')).toBe('c'); 590 | }); 591 | }); 592 | }); 593 | 594 | describe('forEach()', function () { 595 | it('when @op is not a function, should throw', function () { 596 | expect(() => [].asEnumerable().forEach()).toThrow(); 597 | }); 598 | 599 | it('when sequence is not empty, should enumerable all elements', function () { 600 | let dest = []; 601 | [1, 2, 3].asEnumerable().forEach(x => dest.push(x)); 602 | expect(dest).toEqual([1, 2, 3]); 603 | }); 604 | 605 | it('when sequence is empty, should not call @op', function () { 606 | let isCalled = false; 607 | [].asEnumerable().forEach(x => isCalled = true); 608 | expect(isCalled).toBe(false); 609 | }); 610 | }); 611 | }); 612 | -------------------------------------------------------------------------------- /src/linq.js: -------------------------------------------------------------------------------- 1 | /* @license 2 | * linq for javascript 3 | * Authors: Anstinus@gmail.com 4 | * License: MIT 5 | */ 6 | 7 | ///////////////////////////////// merge sort algo /////////////////////////////////////////// 8 | 9 | // scan the whole seqence and divide then into sub sequences, each of which 10 | // is natually ordered or contains equal iterms (depend on 'compGroupChecker'). 11 | function* genSubSequences(seq, comp, compGroupChecker) { 12 | let lastVal; 13 | let subSeq = []; 14 | for (let val of seq) { 15 | if (subSeq.length == 0) { 16 | subSeq = [val]; 17 | } else if (compGroupChecker(comp(lastVal, val))) { 18 | subSeq.push(val); 19 | } else { // lastVal > val 20 | yield subSeq; 21 | subSeq = [val]; 22 | } 23 | lastVal = val; 24 | } 25 | if (subSeq && subSeq.length != 0) { 26 | yield subSeq; 27 | } 28 | } 29 | 30 | function isUndefinedOrNull(val) { 31 | return val === undefined || val === null; 32 | } 33 | 34 | // merge values of two sorted sequences into one sequence 35 | function* genTwoMergedSequence(seq1, seq2, comp) { 36 | let seqIter1 = seq1[Symbol.iterator](); 37 | let seqIter2 = seq2[Symbol.iterator](); 38 | let elem1 = seqIter1.next(); 39 | let elem2 = seqIter2.next(); 40 | while (true) { 41 | if (elem1.done && elem2.done) { 42 | return; 43 | } else if (elem1.done && !elem2.done) { 44 | yield elem2.value; 45 | elem2 = seqIter2.next(); 46 | } else if (!elem1.done && elem2.done) { 47 | yield elem1.value; 48 | elem1 = seqIter1.next(); 49 | } else { 50 | if (isUndefinedOrNull(elem1.value)) { 51 | yield elem1.value; 52 | elem1 = seqIter1.next(); 53 | } else if (isUndefinedOrNull(elem2.value)) { 54 | yield elem2.value; 55 | elem2 = seqIter2.next(); 56 | } else if (comp(elem1.value, elem2.value) <= 0) { 57 | yield elem1.value; 58 | elem1 = seqIter1.next(); 59 | } else { 60 | yield elem2.value; 61 | elem2 = seqIter2.next(); 62 | } 63 | } 64 | } 65 | } 66 | 67 | // merge sequences in pairs. generate a new sequence of sequences. 68 | function* genPairMergedSequences(firstSeq, secondSeq, seqIter, comp) { 69 | let seq1 = firstSeq; 70 | let seq2 = secondSeq; 71 | while (true) { 72 | let localSeq1 = seq1; 73 | let localSeq2 = seq2; 74 | yield { 75 | [Symbol.iterator]: function () { 76 | return genTwoMergedSequence(localSeq1, localSeq2, comp) 77 | } 78 | }; 79 | 80 | let elem1 = seqIter.next(); 81 | if (elem1.done) { 82 | return; 83 | } 84 | let elem2 = seqIter.next(); 85 | if (elem2.done) { 86 | yield elem1.value; 87 | return; 88 | } 89 | seq1 = elem1.value; 90 | seq2 = elem2.value; 91 | } 92 | } 93 | 94 | // repeatly merge sub sequences until only one left 95 | function* genMergedAndSortedSequence(seqIter, comp) { 96 | while (true) { 97 | let firstElem = seqIter.next(); 98 | if (firstElem.done) { // empty seq of seqs. so the result should also be empty. 99 | return; 100 | } 101 | 102 | let secondElem = seqIter.next(); 103 | if (secondElem.done) { // only one seq in seq. just use values in it. 104 | yield * firstElem.value[Symbol.iterator](); 105 | return; 106 | } 107 | 108 | seqIter = genPairMergedSequences(firstElem.value, secondElem.value, seqIter, comp); 109 | } 110 | } 111 | 112 | // merge sort algo return an iterator 113 | function genMergeSort(seq, comp) { 114 | // divide values into sub sequences each of which is natually ordered 115 | let seqIter = genSubSequences(seq, comp, x => x <= 0); 116 | // merge all these sub sequences 117 | return genMergedAndSortedSequence(seqIter, comp); 118 | } 119 | 120 | // the sort algo is complicated. I want to test each sub functions 121 | // without export them. so, here is the work around... 122 | export var _mergeSortTestPack = { 123 | genSubSequences, 124 | genTwoMergedSequence, 125 | genMergedAndSortedSequence, 126 | genMergeSort 127 | }; 128 | 129 | ///////////////////////////////// helpers for OrderBy() ///////////////////////////////////// 130 | 131 | const OrderByTempObjectValName = '_orderByVal_'; 132 | 133 | let keyOrValueIter2ValueIter = function* (keyOrValueIter) { 134 | let elem; 135 | while (!(elem = keyOrValueIter.next()).done) { 136 | let keyOrVal = elem.value; 137 | yield keyOrVal[OrderByTempObjectValName] || keyOrVal; 138 | } 139 | } 140 | 141 | let keyOrValueSeq2ValueSeq = function (keyOrValueSeq) { 142 | return { 143 | [Symbol.iterator]: function () { 144 | return keyOrValueIter2ValueIter(keyOrValueSeq[Symbol.iterator]()); 145 | } 146 | } 147 | } 148 | 149 | let orderByImpl = function* (seq, options) { 150 | if (options.length == 0) throw 'Logic error. "options.length" should not be 0.' 151 | 152 | // for current orderBy/thenBy 153 | // if custom @keySelector is used, we will create a new sequence of 154 | // objects with key and value. 155 | // so we could ensure keys are only to be arquired once during sorting. 156 | let [keySelector, comp, isKeyDefault] = options[0]; 157 | let keyOrValSeq = seq; 158 | let keyOrValComp = comp; 159 | if (!isKeyDefault) { 160 | keyOrValComp = (x, y) => comp(x.key, y.key); 161 | keyOrValSeq = { 162 | [Symbol.iterator]: function* () { 163 | for (let val of seq) { 164 | let key = keySelector(val); 165 | yield { 166 | key: key, 167 | [OrderByTempObjectValName]: val 168 | }; 169 | } 170 | } 171 | } 172 | } 173 | // sort 174 | let sortedKeyOrValIter = genMergeSort(keyOrValSeq, keyOrValComp); 175 | 176 | // check remaining options 177 | let remainingOptions = options.slice(1); 178 | if (remainingOptions.length === 0) { 179 | // no more thenBy, just return the result 180 | yield * keyOrValueIter2ValueIter(sortedKeyOrValIter); 181 | } else { 182 | // more thenBy. 183 | // group by current key first and sort each group by remaining sort options 184 | let seqIter = genSubSequences(sortedKeyOrValIter, keyOrValComp, x => x == 0); 185 | let elem; 186 | while (!(elem = seqIter.next()).done) { 187 | let subSeq = elem.value; 188 | let subSortedSeqIter = orderByImpl(keyOrValueSeq2ValueSeq(subSeq), remainingOptions); 189 | yield * keyOrValueIter2ValueIter(subSortedSeqIter); 190 | } 191 | } 192 | } 193 | 194 | let createSortOption = function (keySelector, comp) { 195 | let isKeyDefault = !keySelector; 196 | keySelector = keySelector || (x => x); 197 | return [keySelector, comp, isKeyDefault]; 198 | } 199 | 200 | ///////////////////////////////// Other helpers for Enumerable class ///////////////////////////////////// 201 | 202 | let defaultComp = (x, y) => (x === y ? 0 : (x < y ? -1 : 1)); 203 | let defaultEqual = (x, y) => x === y; 204 | let defaultPred = x => true; 205 | let defaultSelector = x => x; 206 | let defaultTrans = x => x; 207 | 208 | function joinImpl( 209 | _this, 210 | other, 211 | thisKeySelector, 212 | otherKeySelector, 213 | binaryTrans, 214 | equal, 215 | isGroupJoin) { 216 | if (other === undefined || other === null) { 217 | throw 'must provide a "right" sequence for join()'; 218 | } 219 | return new Enumerable(function* () { 220 | // optimization consideration: 221 | // we assume 'this' have few duplicated keys while 'other' have many. 222 | // so we group 'other' to reduce compare times. 223 | // we should not group 'this' anyway because we need to make the result 224 | // be stable for 'this'. 225 | let yGroups = asEnumerable(other).groupBy(otherKeySelector); 226 | for (let x of _this) { 227 | for (let yg of yGroups) { 228 | let xKey = thisKeySelector(x); 229 | let yKey = yg.key; 230 | if (equal(xKey, yKey)) { 231 | let ySeq = yg; 232 | if (isGroupJoin) { 233 | yield binaryTrans(x, ySeq); 234 | } else { 235 | for (let y of ySeq) { 236 | yield binaryTrans(x, y); 237 | } 238 | } 239 | } 240 | } 241 | } 242 | }); 243 | } 244 | 245 | ///////////////////////////////// Enumerable class for building chain ///////////////////////////////////// 246 | 247 | class Enumerable { 248 | constructor(iterator, baseObject) { 249 | this[Symbol.iterator] = iterator; 250 | if (baseObject) { 251 | this._baseObject = baseObject; 252 | } 253 | } 254 | 255 | _isBaseObjectRandomlyAccessible() { 256 | return this._baseObject && 257 | (Array.isArray(this._baseObject) || typeof this._baseObject === 'string'); 258 | } 259 | 260 | _clone() { 261 | let result = new Enumerable(this[Symbol.iterator], this._baseObject); 262 | result._orderByOptions = this._orderByOptions.asEnumerable().toArray(); 263 | return result; 264 | } 265 | 266 | /////////////////////////////////// chain operations /////////////////////////////////// 267 | 268 | skip(n) { 269 | if (!Number.isInteger(n)) { 270 | throw '@n must be an integer.'; 271 | } 272 | let _this = this; 273 | return new Enumerable(function* () { 274 | let startYield = false; 275 | let count = n; 276 | for (let x of _this) { 277 | if (count-- <= 0) { 278 | startYield = true; 279 | } 280 | if (startYield) { 281 | yield x; 282 | } 283 | } 284 | }); 285 | } 286 | 287 | skipWhile(pred) { 288 | if (typeof pred !== 'function') { 289 | throw '@pred must be a function.'; 290 | } 291 | let _this = this; 292 | return new Enumerable(function* () { 293 | let startYield = false; 294 | let index = 0; 295 | for (let x of _this) { 296 | if (!pred(x, index++)) { 297 | startYield = true; 298 | } 299 | if (startYield) { 300 | yield x; 301 | } 302 | } 303 | }); 304 | } 305 | 306 | take(n) { 307 | if (!Number.isInteger(n)) { 308 | throw '@n must be an integer.'; 309 | } 310 | let _this = this; 311 | return new Enumerable(function* () { 312 | let count = n; 313 | for (let x of _this) { 314 | if (count-- > 0) { 315 | yield x; 316 | } else { 317 | break; 318 | } 319 | } 320 | }); 321 | } 322 | 323 | takeWhile(pred) { 324 | if (typeof pred !== 'function') { 325 | throw '@pred must be a function.'; 326 | } 327 | let _this = this; 328 | return new Enumerable(function* () { 329 | let index = 0; 330 | for (let x of _this) { 331 | if (pred(x, index++)) { 332 | yield x; 333 | } else { 334 | break; 335 | } 336 | } 337 | }); 338 | } 339 | 340 | reverse() { 341 | let _this = this; 342 | return new Enumerable(function* () { 343 | let buf; 344 | if (_this._isBaseObjectRandomlyAccessible()) { 345 | buf = _this._baseObject; 346 | } else { 347 | buf = []; 348 | for (let x of _this) { 349 | buf.push(x); 350 | } 351 | } 352 | 353 | for (let i = buf.length - 1; i >= 0; i--) { 354 | yield buf[i]; 355 | } 356 | }); 357 | } 358 | 359 | select(trans) { 360 | if (typeof trans !== 'function') { 361 | throw '@trans must be a function.'; 362 | } 363 | let _this = this; 364 | return new Enumerable(function* () { 365 | let index = 0; 366 | for (let x of _this) { 367 | yield trans(x, index++); 368 | } 369 | }) 370 | } 371 | 372 | where(pred) { 373 | if (typeof pred !== 'function') { 374 | throw '@pred must be a function.'; 375 | } 376 | let _this = this; 377 | return new Enumerable(function* () { 378 | let index = 0; 379 | for (let x of _this) { 380 | if (pred(x, index++)) { 381 | yield x; 382 | } 383 | } 384 | }); 385 | } 386 | 387 | selectMany(genSeq, resultTrans) { 388 | if (typeof genSeq !== 'function') { 389 | throw '@genSeq must be a function.'; 390 | } 391 | let _this = this; 392 | return new Enumerable(function* () { 393 | let index = 0; 394 | for (let x of _this) { 395 | let seq = genSeq(x, index++); 396 | if (resultTrans) { 397 | yield resultTrans(x, seq); 398 | } else { 399 | for (let y of seq) { 400 | yield y; 401 | } 402 | } 403 | } 404 | }); 405 | } 406 | 407 | groupBy(keySelector = defaultSelector, valueSelector = defaultSelector, resultTrans, keyEqual) { 408 | let _this = this; 409 | if (keyEqual) { // for custom @keyEqual 410 | return new Enumerable(function* () { 411 | let groups = []; 412 | for (let x of _this) { 413 | let key = keySelector(x); 414 | let val = valueSelector(x); 415 | // this is a linear searching that makes this branch slow than the branch with default @keyEqual 416 | let existingGroup = asEnumerable(groups).firstOrDefault(g => keyEqual(key, g.key)); 417 | if (!existingGroup) { 418 | existingGroup = { 419 | key: key, 420 | values: [] 421 | }; 422 | groups.push(existingGroup); 423 | } 424 | existingGroup.values.push(val); 425 | } 426 | for (let group of groups) { 427 | if (resultTrans) { 428 | yield resultTrans(group.key, group.values); 429 | } else { 430 | let result = asEnumerable(group.values); 431 | result.key = group.key; 432 | yield result; 433 | } 434 | } 435 | }); 436 | } else { // optimization for default @keyEqual 437 | return new Enumerable(function* () { 438 | let seqMap = new Map(); 439 | for (let x of _this) { 440 | let key = keySelector(x); 441 | let val = valueSelector(x); 442 | if (!seqMap.has(key)) { 443 | seqMap.set(key, []); 444 | } 445 | seqMap.get(key).push(val); 446 | } 447 | for (let [key, valSeq] of seqMap) { 448 | if (resultTrans) { 449 | yield resultTrans(key, valSeq); 450 | } else { 451 | let result = asEnumerable(valSeq); 452 | result.key = key; 453 | yield result; 454 | } 455 | } 456 | }); 457 | 458 | } 459 | } 460 | 461 | orderBy(keySelector, comp = defaultComp) { 462 | // we use external merge sort algo here. It is 463 | // 1. Only need to do one pass scan of the sequence, which is required 464 | // in linq chain. 465 | // 2. It could fit into the executing logic of 'generator' perfectly, 466 | // resulting a totally lazy orderBy(). 467 | let _this = this; 468 | var result = new Enumerable(function* () { 469 | let iter = orderByImpl(_this, this._orderByOptions); 470 | yield * iter; 471 | }); 472 | result._orderByOptions = [createSortOption(keySelector, comp)]; 473 | return result; 474 | } 475 | 476 | 477 | orderByDescending(keySelector, comp = defaultComp) { 478 | return this.orderBy(keySelector, (x, y) => -comp(x, y)); 479 | } 480 | 481 | thenBy(keySelector, comp = defaultComp) { 482 | if (!this._orderByOptions) { 483 | throw 'thenBy() must follow an orderBy()/thenBy().'; 484 | } 485 | // should copy current Enumerable object instead of modify it. 486 | // the current enumerable object may be used again somewhere else. 487 | let result = this._clone(); 488 | result._orderByOptions.push(createSortOption(keySelector, comp)); 489 | return result; 490 | } 491 | 492 | thenByDescending(keySelector, comp = defaultComp) { 493 | return this.thenBy(keySelector, (x, y) => -comp(x, y)); 494 | } 495 | 496 | join( 497 | other, 498 | thisKeySelector = defaultSelector, 499 | otherKeySelector = defaultSelector, 500 | resultTrans = (x, y) => [x, y], 501 | equal = defaultEqual) { 502 | return joinImpl(this, other, thisKeySelector, otherKeySelector, resultTrans, equal, false); 503 | } 504 | 505 | groupJoin( 506 | other, 507 | thisKeySelector = defaultSelector, 508 | otherKeySelector = defaultSelector, 509 | resultTrans = (x, ySeq) => [x, ySeq], 510 | equal = defaultEqual) { 511 | return joinImpl(this, other, thisKeySelector, otherKeySelector, resultTrans, equal, true); 512 | } 513 | 514 | zip(other, resultTrans = (x, y) => [x, y]) { 515 | if (!other) { 516 | throw 'must provide @other'; 517 | } 518 | let _this = this; 519 | return new Enumerable(function* () { 520 | let iter1 = _this[Symbol.iterator](); 521 | let iter2 = other[Symbol.iterator](); 522 | let elem1, elem2; 523 | while (!(elem1 = iter1.next()).done && !(elem2 = iter2.next()).done) { 524 | yield resultTrans(elem1.value, elem2.value); 525 | } 526 | }); 527 | } 528 | 529 | /////////////////////////////////// sequence chain operations /////////////////////////////////// 530 | 531 | concat(other) { 532 | if (!other) { 533 | throw 'must provide @other'; 534 | } 535 | let _this = this; 536 | return new Enumerable(function* () { 537 | for (let x of _this) { 538 | yield x; 539 | } 540 | for (let y of other) { 541 | yield y; 542 | } 543 | }); 544 | } 545 | 546 | otherThan(other, equal) { 547 | if (!other) { 548 | throw 'must provide @other'; 549 | } 550 | if (equal) { 551 | let otherCache = asEnumerable(other).distinct().eval(); 552 | return this.where(x => otherCache.all(y => !equal(x, y))); 553 | } else { // optimization for default === compare 554 | let otherSet; 555 | return this.where(x => { 556 | if (!otherSet) { // optimizae for this is empty 557 | otherSet = asEnumerable(other).toSet(); 558 | } 559 | return !otherSet.has(x); 560 | }); 561 | } 562 | } 563 | 564 | /////////////////////////////////// set chain operations /////////////////////////////////// 565 | 566 | distinct(equal) { 567 | let _this = this; 568 | 569 | if (equal) { 570 | return new Enumerable(function* () { 571 | let generated = []; 572 | for (let x of _this) { 573 | if (asEnumerable(generated).all(y => !equal(x, y))) { 574 | generated.push(x); 575 | yield x; 576 | } 577 | } 578 | }); 579 | } else { 580 | return new Enumerable(function* () { 581 | let valSet = new Set(); 582 | for (let x of _this) { 583 | if (valSet.size !== valSet.add(x).size) { 584 | yield x; 585 | } 586 | } 587 | }); 588 | } 589 | } 590 | 591 | union(other, equal) { 592 | if (!other) { 593 | throw 'must provide @other'; 594 | } 595 | return this.concat(other).distinct(equal); 596 | } 597 | 598 | intersect(other, equal) { 599 | if (!other) { 600 | throw 'must provide @other'; 601 | } 602 | if (equal) { 603 | let otherCache = asEnumerable(asEnumerable(other).toArray()); 604 | return this.where(x => otherCache.any(y => equal(x, y))); 605 | } else { 606 | let otherSet; 607 | return this.where(x => { 608 | if (!otherSet) { // put this in loop to optimize when this is empty 609 | otherSet = asEnumerable(other).toSet(); 610 | } 611 | return otherSet.has(x); 612 | }).distinct(); 613 | } 614 | } 615 | 616 | except(other, equal) { 617 | if (!other) { 618 | throw 'must provide @other'; 619 | } 620 | return this.distinct().otherThan(other, equal); 621 | } 622 | 623 | /////////////////////////////////// eval operations /////////////////////////////////// 624 | 625 | all(pred) { 626 | if (typeof pred !== 'function') { 627 | throw 'must provide @pred'; 628 | } 629 | let index = 0; 630 | for (let x of this) { 631 | if (!pred(x, index++)) return false; 632 | } 633 | return true; 634 | } 635 | 636 | any(pred = x => true) { 637 | let index = 0; 638 | for (let x of this) { 639 | if (pred(x, index++)) return true; 640 | } 641 | return false; 642 | } 643 | 644 | singleOrDefault(pred = x => true, throwWhenNotFound) { 645 | let chosen; 646 | let alreadyMet = false; 647 | let index = 0; 648 | for (let x of this) { 649 | if (pred(x, index++)) { 650 | if (alreadyMet) { 651 | throw 'more than one element match.'; 652 | } else { 653 | alreadyMet = true; 654 | chosen = x; 655 | } 656 | } 657 | } 658 | if (throwWhenNotFound && !alreadyMet) { 659 | throw 'no element found for specified @pred.'; 660 | } 661 | return chosen; 662 | } 663 | 664 | single(pred = x => true) { 665 | return this.singleOrDefault(pred, true); 666 | } 667 | 668 | count(pred) { 669 | // optimize for array 670 | if (!pred && this._isBaseObjectRandomlyAccessible()) { 671 | return this._baseObject.length; 672 | } 673 | 674 | pred = pred || (x => true); 675 | let result = 0; 676 | for (let x of this) { 677 | if (pred(x)) { 678 | result++; 679 | } 680 | } 681 | return result; 682 | } 683 | 684 | contains(val, comp = (x, y) => x === y) { 685 | return this.any(x => comp(x, val)); 686 | } 687 | 688 | elementAtOrDefault(index, throwWhenNotFound) { 689 | if (!Number.isInteger(index)) { 690 | throw '@index must be an integer'; 691 | } 692 | 693 | if (this._isBaseObjectRandomlyAccessible()) { 694 | if (throwWhenNotFound && (index < 0 || index >= this._baseObject.length)) { 695 | throw 'No element found at specified index.'; 696 | } 697 | return this._baseObject[index]; 698 | } 699 | 700 | let currentIndex = 0; 701 | for (let x of this) { 702 | if (currentIndex++ === index) { 703 | return x; 704 | } 705 | } 706 | if (throwWhenNotFound) { 707 | throw 'No element found at specified index.'; 708 | } 709 | } 710 | 711 | elementAt(index) { 712 | return this.elementAtOrDefault(index, true); 713 | } 714 | 715 | firstOrDefault(pred = x => true, throwWhenNotFound) { 716 | let index = 0; 717 | for (let x of this) { 718 | if (pred(x, index++)) { 719 | return x; 720 | } 721 | } 722 | if (throwWhenNotFound) { 723 | throw 'no elment found for specified @pred'; 724 | } 725 | } 726 | 727 | first(pred = x => true) { 728 | return this.firstOrDefault(pred, true); 729 | } 730 | 731 | 732 | lastOrDefault(pred, throwWhenNotFound) { 733 | let isDefaultPred = !pred; 734 | pred = pred || (x => true); 735 | 736 | // optimization for Array 737 | if (this._isBaseObjectRandomlyAccessible()) { 738 | let index = this._baseObject.length; 739 | while (index-- > 0) { 740 | var x = this._baseObject[index]; 741 | if (pred(x, index)) { 742 | return x; 743 | } 744 | } 745 | if (throwWhenNotFound) { 746 | throw 'no element found for specified @pred'; 747 | } 748 | return undefined; 749 | } 750 | 751 | // optimization for simple last() 752 | // we only need one element buf 753 | if (isDefaultPred) { 754 | let buf; 755 | let notEmpty = false; 756 | for (let x of this) { 757 | notEmpty = true; 758 | buf = x; 759 | } 760 | if (throwWhenNotFound && !notEmpty) { 761 | throw 'no element found for specified @pred'; 762 | } 763 | return buf; 764 | } 765 | 766 | // normal 767 | return this.reverse().firstOrDefault(pred, throwWhenNotFound); 768 | } 769 | 770 | last(pred) { 771 | return this.lastOrDefault(pred, true); 772 | } 773 | 774 | defaultIfEmpty(val) { 775 | return this.any() ? this : (val === undefined ? empty() : asEnumerable([val])); 776 | } 777 | 778 | sequenceEqual(other, comp = (x, y) => x === y) { 779 | let iter1 = this[Symbol.iterator](); 780 | let iter2 = other[Symbol.iterator](); 781 | let elem1, elem2; 782 | while (true) { 783 | elem1 = iter1.next(); 784 | elem2 = iter2.next(); 785 | if (elem1.done || elem2.done) break; 786 | if (!comp(elem1.value, elem2.value)) { 787 | return false; 788 | } 789 | } 790 | return elem1.done && elem2.done; 791 | } 792 | 793 | _minMaxImpl(keySelector, comp) { 794 | let minMaxKey = undefined; 795 | let minMaxItem = undefined; 796 | let index = 0; 797 | for (let item of this) { 798 | let key = keySelector(item, index++); 799 | if (minMaxKey === undefined) { 800 | [minMaxKey, minMaxItem] = [key, item]; 801 | } else { 802 | if (comp(key, minMaxKey)) { 803 | [minMaxKey, minMaxItem] = [key, item]; 804 | } 805 | } 806 | } 807 | return minMaxKey; 808 | } 809 | 810 | min(keySelector = x => x) { 811 | return this._minMaxImpl(keySelector, (x, y) => x < y); 812 | } 813 | 814 | max(keySelector = x => x) { 815 | return this._minMaxImpl(keySelector, (x, y) => x > y); 816 | } 817 | 818 | sum(trans = x => x) { 819 | let result = 0; 820 | let index = 0; 821 | for (let x of this) { 822 | result += trans(x, index++); 823 | } 824 | return result; 825 | } 826 | 827 | average(trans = x => x) { 828 | let result = 0; 829 | let count = 0; 830 | let index = 0; 831 | for (let x of this) { 832 | result += trans(x, index++); 833 | count++; 834 | } 835 | return count === 0 ? 0 : result / count; 836 | } 837 | 838 | 839 | 840 | aggregate(seed, aggFunc, resultTrans) { 841 | if (seed === undefined && aggFunc === undefined) { 842 | throw 'must provide @seed only (treat as @aggFunc) or both @seed and @aggFunc with optional @resultTrans'; 843 | } 844 | 845 | let iter = this[Symbol.iterator](); 846 | 847 | // provide overload: aggregate(aggFunc) 848 | if (seed && !aggFunc && !resultTrans) { 849 | aggFunc = seed; 850 | seed = iter.next().value; 851 | } 852 | 853 | resultTrans = resultTrans || (x => x); 854 | while (true) { 855 | let elem = iter.next(); 856 | if (elem.done) { 857 | return resultTrans(seed); 858 | } else { 859 | seed = aggFunc(seed, elem.value); 860 | } 861 | } 862 | } 863 | 864 | eval() { 865 | return asEnumerable(this.toArray()); 866 | } 867 | 868 | toArray() { 869 | let result = []; 870 | for (let x of this) { 871 | result.push(x); 872 | } 873 | return result; 874 | } 875 | 876 | toSet() { 877 | let result = new Set(); 878 | for (let x of this) { 879 | result.add(x); 880 | } 881 | return result; 882 | } 883 | 884 | toMap(keySelector, valueSelector) { 885 | return new Map(this.select(x => [keySelector(x), valueSelector(x)])); 886 | } 887 | 888 | forEach(op) { 889 | if (typeof op !== 'function') { 890 | throw '@op must be a function.'; 891 | } 892 | 893 | for (let x of this) { 894 | op(x); 895 | } 896 | } 897 | } 898 | 899 | export function asEnumerable(obj) { 900 | // for suffix form 901 | if (obj === undefined) { 902 | obj = this; 903 | } 904 | // an optimization to avoid uneccessary Enumerable object 905 | if (Enumerable.prototype.isPrototypeOf(obj)) { 906 | return obj; 907 | } 908 | // must be iteratable to be used with linq. 909 | if (!(obj[Symbol.iterator]())) { 910 | throw 'Object does not have a [iterator]. It cannot be used with asEnumerable()'; 911 | } 912 | return new Enumerable(function* () { 913 | yield * obj[Symbol.iterator](); 914 | }, obj); 915 | }; 916 | 917 | export function installAsEnumerable(constructor) { 918 | if (constructor) { 919 | constructor.prototype.asEnumerable = asEnumerable; 920 | } else { 921 | // Note: Do not install asEnumerable directly to Object.prototype 922 | // many code (e.g. angular.ui.router) would create a clean object and 923 | // enumerate all function members of an object and try to call all 924 | // of them which including this unexpected 'asEnumerable' function. 925 | String.prototype.asEnumerable = Array.prototype.asEnumerable = asEnumerable; 926 | } 927 | } 928 | 929 | export function range(start, count) { 930 | return new Enumerable(function* () { 931 | for (let i = start; i < start + count; i++) { 932 | yield i; 933 | } 934 | }); 935 | } 936 | 937 | export function repeat(val, count) { 938 | return new Enumerable(function* () { 939 | let localCount = count; 940 | while (localCount-- > 0) { 941 | yield val; 942 | } 943 | }); 944 | } 945 | 946 | export function empty() { 947 | return new Enumerable(function* () {}); 948 | } 949 | -------------------------------------------------------------------------------- /linq-browser.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define(['exports'], factory); 4 | } else if (typeof exports !== 'undefined') { 5 | factory(exports); 6 | } else { 7 | var mod = { 8 | exports: {} 9 | }; 10 | factory(mod.exports); 11 | global.linq = mod.exports; 12 | } 13 | })(this, function (exports) { 14 | /* @license 15 | * linq for javascript 16 | * Authors: Anstinus@gmail.com 17 | * License: MIT 18 | */ 19 | 20 | 'use strict'; 21 | 22 | exports.__esModule = true; 23 | exports.asEnumerable = asEnumerable; 24 | exports.installAsEnumerable = installAsEnumerable; 25 | exports.range = range; 26 | exports.repeat = repeat; 27 | exports.empty = empty; 28 | var marked0$0 = [genSubSequences, genTwoMergedSequence, genPairMergedSequences, genMergedAndSortedSequence].map(regeneratorRuntime.mark); 29 | 30 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 31 | 32 | function genSubSequences(seq, comp, compGroupChecker) { 33 | var lastVal, subSeq, _iterator, _isArray, _i, _ref, val; 34 | 35 | return regeneratorRuntime.wrap(function genSubSequences$(context$1$0) { 36 | while (1) switch (context$1$0.prev = context$1$0.next) { 37 | case 0: 38 | lastVal = undefined; 39 | subSeq = undefined; 40 | _iterator = seq, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator](); 41 | 42 | case 3: 43 | if (!_isArray) { 44 | context$1$0.next = 9; 45 | break; 46 | } 47 | 48 | if (!(_i >= _iterator.length)) { 49 | context$1$0.next = 6; 50 | break; 51 | } 52 | 53 | return context$1$0.abrupt('break', 28); 54 | 55 | case 6: 56 | _ref = _iterator[_i++]; 57 | context$1$0.next = 13; 58 | break; 59 | 60 | case 9: 61 | _i = _iterator.next(); 62 | 63 | if (!_i.done) { 64 | context$1$0.next = 12; 65 | break; 66 | } 67 | 68 | return context$1$0.abrupt('break', 28); 69 | 70 | case 12: 71 | _ref = _i.value; 72 | 73 | case 13: 74 | val = _ref; 75 | 76 | if (!(lastVal === undefined)) { 77 | context$1$0.next = 18; 78 | break; 79 | } 80 | 81 | subSeq = [val]; 82 | context$1$0.next = 25; 83 | break; 84 | 85 | case 18: 86 | if (!compGroupChecker(comp(lastVal, val))) { 87 | context$1$0.next = 22; 88 | break; 89 | } 90 | 91 | subSeq.push(val); 92 | context$1$0.next = 25; 93 | break; 94 | 95 | case 22: 96 | context$1$0.next = 24; 97 | return subSeq; 98 | 99 | case 24: 100 | subSeq = [val]; 101 | 102 | case 25: 103 | lastVal = val; 104 | 105 | case 26: 106 | context$1$0.next = 3; 107 | break; 108 | 109 | case 28: 110 | if (!subSeq) { 111 | context$1$0.next = 31; 112 | break; 113 | } 114 | 115 | context$1$0.next = 31; 116 | return subSeq; 117 | 118 | case 31: 119 | case 'end': 120 | return context$1$0.stop(); 121 | } 122 | }, marked0$0[0], this); 123 | } 124 | 125 | function genTwoMergedSequence(seq1, seq2, comp) { 126 | var seqIter1, seqIter2, elem1, elem2; 127 | return regeneratorRuntime.wrap(function genTwoMergedSequence$(context$1$0) { 128 | while (1) switch (context$1$0.prev = context$1$0.next) { 129 | case 0: 130 | seqIter1 = seq1[Symbol.iterator](); 131 | seqIter2 = seq2[Symbol.iterator](); 132 | elem1 = seqIter1.next(); 133 | elem2 = seqIter2.next(); 134 | 135 | case 4: 136 | if (!true) { 137 | context$1$0.next = 32; 138 | break; 139 | } 140 | 141 | if (!(elem1.done && elem2.done)) { 142 | context$1$0.next = 9; 143 | break; 144 | } 145 | 146 | return context$1$0.abrupt('return'); 147 | 148 | case 9: 149 | if (!(elem1.done && !elem2.done)) { 150 | context$1$0.next = 15; 151 | break; 152 | } 153 | 154 | context$1$0.next = 12; 155 | return elem2.value; 156 | 157 | case 12: 158 | elem2 = seqIter2.next(); 159 | context$1$0.next = 30; 160 | break; 161 | 162 | case 15: 163 | if (!(!elem1.done && elem2.done)) { 164 | context$1$0.next = 21; 165 | break; 166 | } 167 | 168 | context$1$0.next = 18; 169 | return elem1.value; 170 | 171 | case 18: 172 | elem1 = seqIter1.next(); 173 | context$1$0.next = 30; 174 | break; 175 | 176 | case 21: 177 | if (!(comp(elem1.value, elem2.value) <= 0)) { 178 | context$1$0.next = 27; 179 | break; 180 | } 181 | 182 | context$1$0.next = 24; 183 | return elem1.value; 184 | 185 | case 24: 186 | elem1 = seqIter1.next(); 187 | context$1$0.next = 30; 188 | break; 189 | 190 | case 27: 191 | context$1$0.next = 29; 192 | return elem2.value; 193 | 194 | case 29: 195 | elem2 = seqIter2.next(); 196 | 197 | case 30: 198 | context$1$0.next = 4; 199 | break; 200 | 201 | case 32: 202 | case 'end': 203 | return context$1$0.stop(); 204 | } 205 | }, marked0$0[1], this); 206 | } 207 | 208 | function genPairMergedSequences(firstSeq, secondSeq, seqIter, comp) { 209 | var seq1, seq2, _ref2, elem; 210 | 211 | return regeneratorRuntime.wrap(function genPairMergedSequences$(context$1$0) { 212 | var _this2 = this; 213 | 214 | while (1) switch (context$1$0.prev = context$1$0.next) { 215 | case 0: 216 | seq1 = firstSeq; 217 | seq2 = secondSeq; 218 | 219 | case 2: 220 | if (!true) { 221 | context$1$0.next = 16; 222 | break; 223 | } 224 | 225 | if (!(seq1 && seq2)) { 226 | context$1$0.next = 5; 227 | break; 228 | } 229 | 230 | return context$1$0.delegateYield(regeneratorRuntime.mark(function callee$1$0() { 231 | var localSeq1, localseq2; 232 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 233 | while (1) switch (context$2$0.prev = context$2$0.next) { 234 | case 0: 235 | localSeq1 = seq1; 236 | localseq2 = seq2; 237 | context$2$0.next = 4; 238 | return (_ref2 = {}, _ref2[Symbol.iterator] = function () { 239 | return genTwoMergedSequence(localSeq1, localseq2, comp); 240 | }, _ref2); 241 | 242 | case 4: 243 | seq1 = seq2 = undefined; 244 | 245 | case 5: 246 | case 'end': 247 | return context$2$0.stop(); 248 | } 249 | }, callee$1$0, _this2); 250 | })(), 't0', 5); 251 | 252 | case 5: 253 | elem = seqIter.next(); 254 | 255 | if (!elem.done) { 256 | context$1$0.next = 13; 257 | break; 258 | } 259 | 260 | if (!seq1) { 261 | context$1$0.next = 10; 262 | break; 263 | } 264 | 265 | context$1$0.next = 10; 266 | return seq1; 267 | 268 | case 10: 269 | return context$1$0.abrupt('return'); 270 | 271 | case 13: 272 | if (!seq1) { 273 | seq1 = elem.value; 274 | } else { 275 | seq2 = elem.value; 276 | } 277 | 278 | case 14: 279 | context$1$0.next = 2; 280 | break; 281 | 282 | case 16: 283 | case 'end': 284 | return context$1$0.stop(); 285 | } 286 | }, marked0$0[2], this); 287 | } 288 | 289 | function genMergedAndSortedSequence(seqIter, comp) { 290 | var firstElem, secondElem; 291 | return regeneratorRuntime.wrap(function genMergedAndSortedSequence$(context$1$0) { 292 | while (1) switch (context$1$0.prev = context$1$0.next) { 293 | case 0: 294 | if (!true) { 295 | context$1$0.next = 11; 296 | break; 297 | } 298 | 299 | firstElem = seqIter.next(); 300 | 301 | if (!firstElem.done) { 302 | context$1$0.next = 4; 303 | break; 304 | } 305 | 306 | return context$1$0.abrupt('return'); 307 | 308 | case 4: 309 | secondElem = seqIter.next(); 310 | 311 | if (!secondElem.done) { 312 | context$1$0.next = 8; 313 | break; 314 | } 315 | 316 | return context$1$0.delegateYield(firstElem.value[Symbol.iterator](), 't0', 7); 317 | 318 | case 7: 319 | return context$1$0.abrupt('return'); 320 | 321 | case 8: 322 | 323 | seqIter = genPairMergedSequences(firstElem.value, secondElem.value, seqIter, comp); 324 | context$1$0.next = 0; 325 | break; 326 | 327 | case 11: 328 | case 'end': 329 | return context$1$0.stop(); 330 | } 331 | }, marked0$0[3], this); 332 | } 333 | 334 | function genMergeSort(seq, comp) { 335 | var seqIter = genSubSequences(seq, comp, function (x) { 336 | return x <= 0; 337 | }); 338 | 339 | return genMergedAndSortedSequence(seqIter, comp); 340 | } 341 | 342 | var _mergeSortTestPack = { 343 | genSubSequences: genSubSequences, 344 | genTwoMergedSequence: genTwoMergedSequence, 345 | genMergedAndSortedSequence: genMergedAndSortedSequence, 346 | genMergeSort: genMergeSort 347 | }; 348 | 349 | exports._mergeSortTestPack = _mergeSortTestPack; 350 | 351 | var OrderByTempObjectValName = '_orderByVal_'; 352 | 353 | var keyOrValueIter2ValueIter = regeneratorRuntime.mark(function keyOrValueIter2ValueIter(keyOrValueIter) { 354 | var elem, keyOrVal; 355 | return regeneratorRuntime.wrap(function keyOrValueIter2ValueIter$(context$1$0) { 356 | while (1) switch (context$1$0.prev = context$1$0.next) { 357 | case 0: 358 | elem = undefined; 359 | 360 | case 1: 361 | if ((elem = keyOrValueIter.next()).done) { 362 | context$1$0.next = 7; 363 | break; 364 | } 365 | 366 | keyOrVal = elem.value; 367 | context$1$0.next = 5; 368 | return keyOrVal[OrderByTempObjectValName] || keyOrVal; 369 | 370 | case 5: 371 | context$1$0.next = 1; 372 | break; 373 | 374 | case 7: 375 | case 'end': 376 | return context$1$0.stop(); 377 | } 378 | }, keyOrValueIter2ValueIter, this); 379 | }); 380 | 381 | var keyOrValueSeq2ValueSeq = function keyOrValueSeq2ValueSeq(keyOrValueSeq) { 382 | var _ref3; 383 | 384 | return (_ref3 = {}, _ref3[Symbol.iterator] = function () { 385 | return keyOrValueIter2ValueIter(keyOrValueSeq[Symbol.iterator]()); 386 | }, _ref3); 387 | }; 388 | 389 | var orderByImpl = regeneratorRuntime.mark(function orderByImpl(seq, options) { 390 | var _options$0, keySelector, comp, isKeyDefault, keyOrValSeq, keyOrValComp, _keyOrValSeq, sortedKeyOrValIter, remainingOptions, seqIter, elem, subSeq, subSortedSeqIter; 391 | 392 | return regeneratorRuntime.wrap(function orderByImpl$(context$1$0) { 393 | while (1) switch (context$1$0.prev = context$1$0.next) { 394 | case 0: 395 | if (!(options.length == 0)) { 396 | context$1$0.next = 2; 397 | break; 398 | } 399 | 400 | throw 'Logic error. "options.length" should not be 0.'; 401 | 402 | case 2: 403 | _options$0 = options[0]; 404 | keySelector = _options$0[0]; 405 | comp = _options$0[1]; 406 | isKeyDefault = _options$0[2]; 407 | keyOrValSeq = seq; 408 | keyOrValComp = comp; 409 | 410 | if (!isKeyDefault) { 411 | keyOrValComp = function (x, y) { 412 | return comp(x.key, y.key); 413 | }; 414 | keyOrValSeq = (_keyOrValSeq = {}, _keyOrValSeq[Symbol.iterator] = regeneratorRuntime.mark(function callee$1$0() { 415 | var _iterator2, _isArray2, _i2, _ref5, _ref4, val, key; 416 | 417 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 418 | while (1) switch (context$2$0.prev = context$2$0.next) { 419 | case 0: 420 | _iterator2 = seq, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator](); 421 | 422 | case 1: 423 | if (!_isArray2) { 424 | context$2$0.next = 7; 425 | break; 426 | } 427 | 428 | if (!(_i2 >= _iterator2.length)) { 429 | context$2$0.next = 4; 430 | break; 431 | } 432 | 433 | return context$2$0.abrupt('break', 17); 434 | 435 | case 4: 436 | _ref4 = _iterator2[_i2++]; 437 | context$2$0.next = 11; 438 | break; 439 | 440 | case 7: 441 | _i2 = _iterator2.next(); 442 | 443 | if (!_i2.done) { 444 | context$2$0.next = 10; 445 | break; 446 | } 447 | 448 | return context$2$0.abrupt('break', 17); 449 | 450 | case 10: 451 | _ref4 = _i2.value; 452 | 453 | case 11: 454 | val = _ref4; 455 | key = keySelector(val); 456 | context$2$0.next = 15; 457 | return (_ref5 = { 458 | key: key 459 | }, _ref5[OrderByTempObjectValName] = val, _ref5); 460 | 461 | case 15: 462 | context$2$0.next = 1; 463 | break; 464 | 465 | case 17: 466 | case 'end': 467 | return context$2$0.stop(); 468 | } 469 | }, callee$1$0, this); 470 | }), _keyOrValSeq); 471 | } 472 | sortedKeyOrValIter = genMergeSort(keyOrValSeq, keyOrValComp); 473 | remainingOptions = options.slice(1); 474 | 475 | if (!(remainingOptions.length === 0)) { 476 | context$1$0.next = 15; 477 | break; 478 | } 479 | 480 | return context$1$0.delegateYield(keyOrValueIter2ValueIter(sortedKeyOrValIter), 't0', 13); 481 | 482 | case 13: 483 | context$1$0.next = 23; 484 | break; 485 | 486 | case 15: 487 | seqIter = genSubSequences(sortedKeyOrValIter, keyOrValComp, function (x) { 488 | return x == 0; 489 | }); 490 | elem = undefined; 491 | 492 | case 17: 493 | if ((elem = seqIter.next()).done) { 494 | context$1$0.next = 23; 495 | break; 496 | } 497 | 498 | subSeq = elem.value; 499 | subSortedSeqIter = orderByImpl(keyOrValueSeq2ValueSeq(subSeq), remainingOptions); 500 | return context$1$0.delegateYield(keyOrValueIter2ValueIter(subSortedSeqIter), 't1', 21); 501 | 502 | case 21: 503 | context$1$0.next = 17; 504 | break; 505 | 506 | case 23: 507 | case 'end': 508 | return context$1$0.stop(); 509 | } 510 | }, orderByImpl, this); 511 | }); 512 | 513 | var createSortOption = function createSortOption(keySelector, comp) { 514 | var isKeyDefault = !keySelector; 515 | keySelector = keySelector || function (x) { 516 | return x; 517 | }; 518 | return [keySelector, comp, isKeyDefault]; 519 | }; 520 | 521 | var defaultComp = function defaultComp(x, y) { 522 | return x === y ? 0 : x < y ? -1 : 1; 523 | }; 524 | var defaultEqual = function defaultEqual(x, y) { 525 | return x === y; 526 | }; 527 | var defaultPred = function defaultPred(x) { 528 | return true; 529 | }; 530 | var defaultSelector = function defaultSelector(x) { 531 | return x; 532 | }; 533 | var defaultTrans = function defaultTrans(x) { 534 | return x; 535 | }; 536 | 537 | function joinImpl(_this, other, thisKeySelector, otherKeySelector, binaryTrans, equal, isGroupJoin) { 538 | if (other === undefined || other === null) { 539 | throw 'must provide a "right" sequence for join()'; 540 | } 541 | return new Enumerable(regeneratorRuntime.mark(function callee$1$0() { 542 | var yGroups, _iterator3, _isArray3, _i3, _ref6, x, _iterator4, _isArray4, _i4, _ref7, yg, xKey, yKey, ySeq, _iterator5, _isArray5, _i5, _ref8, y; 543 | 544 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 545 | while (1) switch (context$2$0.prev = context$2$0.next) { 546 | case 0: 547 | yGroups = asEnumerable(other).groupBy(otherKeySelector); 548 | _iterator3 = _this, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator](); 549 | 550 | case 2: 551 | if (!_isArray3) { 552 | context$2$0.next = 8; 553 | break; 554 | } 555 | 556 | if (!(_i3 >= _iterator3.length)) { 557 | context$2$0.next = 5; 558 | break; 559 | } 560 | 561 | return context$2$0.abrupt('break', 54); 562 | 563 | case 5: 564 | _ref6 = _iterator3[_i3++]; 565 | context$2$0.next = 12; 566 | break; 567 | 568 | case 8: 569 | _i3 = _iterator3.next(); 570 | 571 | if (!_i3.done) { 572 | context$2$0.next = 11; 573 | break; 574 | } 575 | 576 | return context$2$0.abrupt('break', 54); 577 | 578 | case 11: 579 | _ref6 = _i3.value; 580 | 581 | case 12: 582 | x = _ref6; 583 | _iterator4 = yGroups, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator](); 584 | 585 | case 14: 586 | if (!_isArray4) { 587 | context$2$0.next = 20; 588 | break; 589 | } 590 | 591 | if (!(_i4 >= _iterator4.length)) { 592 | context$2$0.next = 17; 593 | break; 594 | } 595 | 596 | return context$2$0.abrupt('break', 52); 597 | 598 | case 17: 599 | _ref7 = _iterator4[_i4++]; 600 | context$2$0.next = 24; 601 | break; 602 | 603 | case 20: 604 | _i4 = _iterator4.next(); 605 | 606 | if (!_i4.done) { 607 | context$2$0.next = 23; 608 | break; 609 | } 610 | 611 | return context$2$0.abrupt('break', 52); 612 | 613 | case 23: 614 | _ref7 = _i4.value; 615 | 616 | case 24: 617 | yg = _ref7; 618 | xKey = thisKeySelector(x); 619 | yKey = yg.key; 620 | 621 | if (!equal(xKey, yKey)) { 622 | context$2$0.next = 50; 623 | break; 624 | } 625 | 626 | ySeq = yg; 627 | 628 | if (!isGroupJoin) { 629 | context$2$0.next = 34; 630 | break; 631 | } 632 | 633 | context$2$0.next = 32; 634 | return binaryTrans(x, ySeq); 635 | 636 | case 32: 637 | context$2$0.next = 50; 638 | break; 639 | 640 | case 34: 641 | _iterator5 = ySeq, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator](); 642 | 643 | case 35: 644 | if (!_isArray5) { 645 | context$2$0.next = 41; 646 | break; 647 | } 648 | 649 | if (!(_i5 >= _iterator5.length)) { 650 | context$2$0.next = 38; 651 | break; 652 | } 653 | 654 | return context$2$0.abrupt('break', 50); 655 | 656 | case 38: 657 | _ref8 = _iterator5[_i5++]; 658 | context$2$0.next = 45; 659 | break; 660 | 661 | case 41: 662 | _i5 = _iterator5.next(); 663 | 664 | if (!_i5.done) { 665 | context$2$0.next = 44; 666 | break; 667 | } 668 | 669 | return context$2$0.abrupt('break', 50); 670 | 671 | case 44: 672 | _ref8 = _i5.value; 673 | 674 | case 45: 675 | y = _ref8; 676 | context$2$0.next = 48; 677 | return binaryTrans(x, y); 678 | 679 | case 48: 680 | context$2$0.next = 35; 681 | break; 682 | 683 | case 50: 684 | context$2$0.next = 14; 685 | break; 686 | 687 | case 52: 688 | context$2$0.next = 2; 689 | break; 690 | 691 | case 54: 692 | case 'end': 693 | return context$2$0.stop(); 694 | } 695 | }, callee$1$0, this); 696 | })); 697 | } 698 | 699 | var Enumerable = (function () { 700 | function Enumerable(iterator, baseObject) { 701 | _classCallCheck(this, Enumerable); 702 | 703 | this[Symbol.iterator] = iterator; 704 | if (baseObject) { 705 | this._baseObject = baseObject; 706 | } 707 | } 708 | 709 | Enumerable.prototype._isBaseObjectRandomlyAccessible = function _isBaseObjectRandomlyAccessible() { 710 | return this._baseObject && (Array.isArray(this._baseObject) || typeof this._baseObject === 'string'); 711 | }; 712 | 713 | Enumerable.prototype._clone = function _clone() { 714 | var result = new Enumerable(this[Symbol.iterator], this._baseObject); 715 | result._orderByOptions = this._orderByOptions.asEnumerable().toArray(); 716 | return result; 717 | }; 718 | 719 | Enumerable.prototype.skip = function skip(n) { 720 | if (!Number.isInteger(n)) { 721 | throw '@n must be an integer.'; 722 | } 723 | var _this = this; 724 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 725 | var startYield, count, _iterator6, _isArray6, _i6, _ref9, x; 726 | 727 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 728 | while (1) switch (context$3$0.prev = context$3$0.next) { 729 | case 0: 730 | startYield = false; 731 | count = n; 732 | _iterator6 = _this, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator](); 733 | 734 | case 3: 735 | if (!_isArray6) { 736 | context$3$0.next = 9; 737 | break; 738 | } 739 | 740 | if (!(_i6 >= _iterator6.length)) { 741 | context$3$0.next = 6; 742 | break; 743 | } 744 | 745 | return context$3$0.abrupt('break', 20); 746 | 747 | case 6: 748 | _ref9 = _iterator6[_i6++]; 749 | context$3$0.next = 13; 750 | break; 751 | 752 | case 9: 753 | _i6 = _iterator6.next(); 754 | 755 | if (!_i6.done) { 756 | context$3$0.next = 12; 757 | break; 758 | } 759 | 760 | return context$3$0.abrupt('break', 20); 761 | 762 | case 12: 763 | _ref9 = _i6.value; 764 | 765 | case 13: 766 | x = _ref9; 767 | 768 | if (count-- <= 0) { 769 | startYield = true; 770 | } 771 | 772 | if (!startYield) { 773 | context$3$0.next = 18; 774 | break; 775 | } 776 | 777 | context$3$0.next = 18; 778 | return x; 779 | 780 | case 18: 781 | context$3$0.next = 3; 782 | break; 783 | 784 | case 20: 785 | case 'end': 786 | return context$3$0.stop(); 787 | } 788 | }, callee$2$0, this); 789 | })); 790 | }; 791 | 792 | Enumerable.prototype.skipWhile = function skipWhile(pred) { 793 | if (typeof pred !== 'function') { 794 | throw '@pred must be a function.'; 795 | } 796 | var _this = this; 797 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 798 | var startYield, index, _iterator7, _isArray7, _i7, _ref10, x; 799 | 800 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 801 | while (1) switch (context$3$0.prev = context$3$0.next) { 802 | case 0: 803 | startYield = false; 804 | index = 0; 805 | _iterator7 = _this, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator](); 806 | 807 | case 3: 808 | if (!_isArray7) { 809 | context$3$0.next = 9; 810 | break; 811 | } 812 | 813 | if (!(_i7 >= _iterator7.length)) { 814 | context$3$0.next = 6; 815 | break; 816 | } 817 | 818 | return context$3$0.abrupt('break', 20); 819 | 820 | case 6: 821 | _ref10 = _iterator7[_i7++]; 822 | context$3$0.next = 13; 823 | break; 824 | 825 | case 9: 826 | _i7 = _iterator7.next(); 827 | 828 | if (!_i7.done) { 829 | context$3$0.next = 12; 830 | break; 831 | } 832 | 833 | return context$3$0.abrupt('break', 20); 834 | 835 | case 12: 836 | _ref10 = _i7.value; 837 | 838 | case 13: 839 | x = _ref10; 840 | 841 | if (!pred(x, index++)) { 842 | startYield = true; 843 | } 844 | 845 | if (!startYield) { 846 | context$3$0.next = 18; 847 | break; 848 | } 849 | 850 | context$3$0.next = 18; 851 | return x; 852 | 853 | case 18: 854 | context$3$0.next = 3; 855 | break; 856 | 857 | case 20: 858 | case 'end': 859 | return context$3$0.stop(); 860 | } 861 | }, callee$2$0, this); 862 | })); 863 | }; 864 | 865 | Enumerable.prototype.take = function take(n) { 866 | if (!Number.isInteger(n)) { 867 | throw '@n must be an integer.'; 868 | } 869 | var _this = this; 870 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 871 | var count, _iterator8, _isArray8, _i8, _ref11, x; 872 | 873 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 874 | while (1) switch (context$3$0.prev = context$3$0.next) { 875 | case 0: 876 | count = n; 877 | _iterator8 = _this, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator](); 878 | 879 | case 2: 880 | if (!_isArray8) { 881 | context$3$0.next = 8; 882 | break; 883 | } 884 | 885 | if (!(_i8 >= _iterator8.length)) { 886 | context$3$0.next = 5; 887 | break; 888 | } 889 | 890 | return context$3$0.abrupt('break', 21); 891 | 892 | case 5: 893 | _ref11 = _iterator8[_i8++]; 894 | context$3$0.next = 12; 895 | break; 896 | 897 | case 8: 898 | _i8 = _iterator8.next(); 899 | 900 | if (!_i8.done) { 901 | context$3$0.next = 11; 902 | break; 903 | } 904 | 905 | return context$3$0.abrupt('break', 21); 906 | 907 | case 11: 908 | _ref11 = _i8.value; 909 | 910 | case 12: 911 | x = _ref11; 912 | 913 | if (!(count-- > 0)) { 914 | context$3$0.next = 18; 915 | break; 916 | } 917 | 918 | context$3$0.next = 16; 919 | return x; 920 | 921 | case 16: 922 | context$3$0.next = 19; 923 | break; 924 | 925 | case 18: 926 | return context$3$0.abrupt('break', 21); 927 | 928 | case 19: 929 | context$3$0.next = 2; 930 | break; 931 | 932 | case 21: 933 | case 'end': 934 | return context$3$0.stop(); 935 | } 936 | }, callee$2$0, this); 937 | })); 938 | }; 939 | 940 | Enumerable.prototype.takeWhile = function takeWhile(pred) { 941 | if (typeof pred !== 'function') { 942 | throw '@pred must be a function.'; 943 | } 944 | var _this = this; 945 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 946 | var index, _iterator9, _isArray9, _i9, _ref12, x; 947 | 948 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 949 | while (1) switch (context$3$0.prev = context$3$0.next) { 950 | case 0: 951 | index = 0; 952 | _iterator9 = _this, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator](); 953 | 954 | case 2: 955 | if (!_isArray9) { 956 | context$3$0.next = 8; 957 | break; 958 | } 959 | 960 | if (!(_i9 >= _iterator9.length)) { 961 | context$3$0.next = 5; 962 | break; 963 | } 964 | 965 | return context$3$0.abrupt('break', 21); 966 | 967 | case 5: 968 | _ref12 = _iterator9[_i9++]; 969 | context$3$0.next = 12; 970 | break; 971 | 972 | case 8: 973 | _i9 = _iterator9.next(); 974 | 975 | if (!_i9.done) { 976 | context$3$0.next = 11; 977 | break; 978 | } 979 | 980 | return context$3$0.abrupt('break', 21); 981 | 982 | case 11: 983 | _ref12 = _i9.value; 984 | 985 | case 12: 986 | x = _ref12; 987 | 988 | if (!pred(x, index++)) { 989 | context$3$0.next = 18; 990 | break; 991 | } 992 | 993 | context$3$0.next = 16; 994 | return x; 995 | 996 | case 16: 997 | context$3$0.next = 19; 998 | break; 999 | 1000 | case 18: 1001 | return context$3$0.abrupt('break', 21); 1002 | 1003 | case 19: 1004 | context$3$0.next = 2; 1005 | break; 1006 | 1007 | case 21: 1008 | case 'end': 1009 | return context$3$0.stop(); 1010 | } 1011 | }, callee$2$0, this); 1012 | })); 1013 | }; 1014 | 1015 | Enumerable.prototype.reverse = function reverse() { 1016 | var _this = this; 1017 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1018 | var buf, _iterator10, _isArray10, _i10, _ref13, x, i; 1019 | 1020 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1021 | while (1) switch (context$3$0.prev = context$3$0.next) { 1022 | case 0: 1023 | buf = undefined; 1024 | 1025 | if (!_this._isBaseObjectRandomlyAccessible()) { 1026 | context$3$0.next = 5; 1027 | break; 1028 | } 1029 | 1030 | buf = _this._baseObject; 1031 | context$3$0.next = 21; 1032 | break; 1033 | 1034 | case 5: 1035 | buf = []; 1036 | _iterator10 = _this, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator](); 1037 | 1038 | case 7: 1039 | if (!_isArray10) { 1040 | context$3$0.next = 13; 1041 | break; 1042 | } 1043 | 1044 | if (!(_i10 >= _iterator10.length)) { 1045 | context$3$0.next = 10; 1046 | break; 1047 | } 1048 | 1049 | return context$3$0.abrupt('break', 21); 1050 | 1051 | case 10: 1052 | _ref13 = _iterator10[_i10++]; 1053 | context$3$0.next = 17; 1054 | break; 1055 | 1056 | case 13: 1057 | _i10 = _iterator10.next(); 1058 | 1059 | if (!_i10.done) { 1060 | context$3$0.next = 16; 1061 | break; 1062 | } 1063 | 1064 | return context$3$0.abrupt('break', 21); 1065 | 1066 | case 16: 1067 | _ref13 = _i10.value; 1068 | 1069 | case 17: 1070 | x = _ref13; 1071 | 1072 | buf.push(x); 1073 | 1074 | case 19: 1075 | context$3$0.next = 7; 1076 | break; 1077 | 1078 | case 21: 1079 | i = buf.length - 1; 1080 | 1081 | case 22: 1082 | if (!(i >= 0)) { 1083 | context$3$0.next = 28; 1084 | break; 1085 | } 1086 | 1087 | context$3$0.next = 25; 1088 | return buf[i]; 1089 | 1090 | case 25: 1091 | i--; 1092 | context$3$0.next = 22; 1093 | break; 1094 | 1095 | case 28: 1096 | case 'end': 1097 | return context$3$0.stop(); 1098 | } 1099 | }, callee$2$0, this); 1100 | })); 1101 | }; 1102 | 1103 | Enumerable.prototype.select = function select(trans) { 1104 | if (typeof trans !== 'function') { 1105 | throw '@trans must be a function.'; 1106 | } 1107 | var _this = this; 1108 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1109 | var index, _iterator11, _isArray11, _i11, _ref14, x; 1110 | 1111 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1112 | while (1) switch (context$3$0.prev = context$3$0.next) { 1113 | case 0: 1114 | index = 0; 1115 | _iterator11 = _this, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator](); 1116 | 1117 | case 2: 1118 | if (!_isArray11) { 1119 | context$3$0.next = 8; 1120 | break; 1121 | } 1122 | 1123 | if (!(_i11 >= _iterator11.length)) { 1124 | context$3$0.next = 5; 1125 | break; 1126 | } 1127 | 1128 | return context$3$0.abrupt('break', 17); 1129 | 1130 | case 5: 1131 | _ref14 = _iterator11[_i11++]; 1132 | context$3$0.next = 12; 1133 | break; 1134 | 1135 | case 8: 1136 | _i11 = _iterator11.next(); 1137 | 1138 | if (!_i11.done) { 1139 | context$3$0.next = 11; 1140 | break; 1141 | } 1142 | 1143 | return context$3$0.abrupt('break', 17); 1144 | 1145 | case 11: 1146 | _ref14 = _i11.value; 1147 | 1148 | case 12: 1149 | x = _ref14; 1150 | context$3$0.next = 15; 1151 | return trans(x, index++); 1152 | 1153 | case 15: 1154 | context$3$0.next = 2; 1155 | break; 1156 | 1157 | case 17: 1158 | case 'end': 1159 | return context$3$0.stop(); 1160 | } 1161 | }, callee$2$0, this); 1162 | })); 1163 | }; 1164 | 1165 | Enumerable.prototype.where = function where(pred) { 1166 | if (typeof pred !== 'function') { 1167 | throw '@pred must be a function.'; 1168 | } 1169 | var _this = this; 1170 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1171 | var index, _iterator12, _isArray12, _i12, _ref15, x; 1172 | 1173 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1174 | while (1) switch (context$3$0.prev = context$3$0.next) { 1175 | case 0: 1176 | index = 0; 1177 | _iterator12 = _this, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator](); 1178 | 1179 | case 2: 1180 | if (!_isArray12) { 1181 | context$3$0.next = 8; 1182 | break; 1183 | } 1184 | 1185 | if (!(_i12 >= _iterator12.length)) { 1186 | context$3$0.next = 5; 1187 | break; 1188 | } 1189 | 1190 | return context$3$0.abrupt('break', 18); 1191 | 1192 | case 5: 1193 | _ref15 = _iterator12[_i12++]; 1194 | context$3$0.next = 12; 1195 | break; 1196 | 1197 | case 8: 1198 | _i12 = _iterator12.next(); 1199 | 1200 | if (!_i12.done) { 1201 | context$3$0.next = 11; 1202 | break; 1203 | } 1204 | 1205 | return context$3$0.abrupt('break', 18); 1206 | 1207 | case 11: 1208 | _ref15 = _i12.value; 1209 | 1210 | case 12: 1211 | x = _ref15; 1212 | 1213 | if (!pred(x, index++)) { 1214 | context$3$0.next = 16; 1215 | break; 1216 | } 1217 | 1218 | context$3$0.next = 16; 1219 | return x; 1220 | 1221 | case 16: 1222 | context$3$0.next = 2; 1223 | break; 1224 | 1225 | case 18: 1226 | case 'end': 1227 | return context$3$0.stop(); 1228 | } 1229 | }, callee$2$0, this); 1230 | })); 1231 | }; 1232 | 1233 | Enumerable.prototype.selectMany = function selectMany(genSeq, resultTrans) { 1234 | if (typeof genSeq !== 'function') { 1235 | throw '@genSeq must be a function.'; 1236 | } 1237 | var _this = this; 1238 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1239 | var index, _iterator13, _isArray13, _i13, _ref16, x, seq, _iterator14, _isArray14, _i14, _ref17, y; 1240 | 1241 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1242 | while (1) switch (context$3$0.prev = context$3$0.next) { 1243 | case 0: 1244 | index = 0; 1245 | _iterator13 = _this, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator](); 1246 | 1247 | case 2: 1248 | if (!_isArray13) { 1249 | context$3$0.next = 8; 1250 | break; 1251 | } 1252 | 1253 | if (!(_i13 >= _iterator13.length)) { 1254 | context$3$0.next = 5; 1255 | break; 1256 | } 1257 | 1258 | return context$3$0.abrupt('break', 37); 1259 | 1260 | case 5: 1261 | _ref16 = _iterator13[_i13++]; 1262 | context$3$0.next = 12; 1263 | break; 1264 | 1265 | case 8: 1266 | _i13 = _iterator13.next(); 1267 | 1268 | if (!_i13.done) { 1269 | context$3$0.next = 11; 1270 | break; 1271 | } 1272 | 1273 | return context$3$0.abrupt('break', 37); 1274 | 1275 | case 11: 1276 | _ref16 = _i13.value; 1277 | 1278 | case 12: 1279 | x = _ref16; 1280 | seq = genSeq(x, index++); 1281 | 1282 | if (!resultTrans) { 1283 | context$3$0.next = 19; 1284 | break; 1285 | } 1286 | 1287 | context$3$0.next = 17; 1288 | return resultTrans(x, seq); 1289 | 1290 | case 17: 1291 | context$3$0.next = 35; 1292 | break; 1293 | 1294 | case 19: 1295 | _iterator14 = seq, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator](); 1296 | 1297 | case 20: 1298 | if (!_isArray14) { 1299 | context$3$0.next = 26; 1300 | break; 1301 | } 1302 | 1303 | if (!(_i14 >= _iterator14.length)) { 1304 | context$3$0.next = 23; 1305 | break; 1306 | } 1307 | 1308 | return context$3$0.abrupt('break', 35); 1309 | 1310 | case 23: 1311 | _ref17 = _iterator14[_i14++]; 1312 | context$3$0.next = 30; 1313 | break; 1314 | 1315 | case 26: 1316 | _i14 = _iterator14.next(); 1317 | 1318 | if (!_i14.done) { 1319 | context$3$0.next = 29; 1320 | break; 1321 | } 1322 | 1323 | return context$3$0.abrupt('break', 35); 1324 | 1325 | case 29: 1326 | _ref17 = _i14.value; 1327 | 1328 | case 30: 1329 | y = _ref17; 1330 | context$3$0.next = 33; 1331 | return y; 1332 | 1333 | case 33: 1334 | context$3$0.next = 20; 1335 | break; 1336 | 1337 | case 35: 1338 | context$3$0.next = 2; 1339 | break; 1340 | 1341 | case 37: 1342 | case 'end': 1343 | return context$3$0.stop(); 1344 | } 1345 | }, callee$2$0, this); 1346 | })); 1347 | }; 1348 | 1349 | Enumerable.prototype.groupBy = function groupBy(keySelector, valueSelector, resultTrans, keyEqual) { 1350 | if (keySelector === undefined) keySelector = defaultSelector; 1351 | if (valueSelector === undefined) valueSelector = defaultSelector; 1352 | 1353 | var _this = this; 1354 | if (keyEqual) { 1355 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1356 | var groups, _loop, _iterator15, _isArray15, _i15, _ref18, _ret2, _iterator16, _isArray16, _i16, _ref19, group, result; 1357 | 1358 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1359 | while (1) switch (context$3$0.prev = context$3$0.next) { 1360 | case 0: 1361 | groups = []; 1362 | 1363 | _loop = function () { 1364 | if (_isArray15) { 1365 | if (_i15 >= _iterator15.length) return 'break'; 1366 | _ref18 = _iterator15[_i15++]; 1367 | } else { 1368 | _i15 = _iterator15.next(); 1369 | if (_i15.done) return 'break'; 1370 | _ref18 = _i15.value; 1371 | } 1372 | 1373 | var x = _ref18; 1374 | 1375 | var key = keySelector(x); 1376 | var val = valueSelector(x); 1377 | 1378 | var existingGroup = asEnumerable(groups).firstOrDefault(function (g) { 1379 | return keyEqual(key, g.key); 1380 | }); 1381 | if (!existingGroup) { 1382 | existingGroup = { 1383 | key: key, 1384 | values: [] 1385 | }; 1386 | groups.push(existingGroup); 1387 | } 1388 | existingGroup.values.push(val); 1389 | }; 1390 | 1391 | _iterator15 = _this, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator](); 1392 | 1393 | case 3: 1394 | _ret2 = _loop(); 1395 | 1396 | if (!(_ret2 === 'break')) { 1397 | context$3$0.next = 6; 1398 | break; 1399 | } 1400 | 1401 | return context$3$0.abrupt('break', 8); 1402 | 1403 | case 6: 1404 | context$3$0.next = 3; 1405 | break; 1406 | 1407 | case 8: 1408 | _iterator16 = groups, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator](); 1409 | 1410 | case 9: 1411 | if (!_isArray16) { 1412 | context$3$0.next = 15; 1413 | break; 1414 | } 1415 | 1416 | if (!(_i16 >= _iterator16.length)) { 1417 | context$3$0.next = 12; 1418 | break; 1419 | } 1420 | 1421 | return context$3$0.abrupt('break', 31); 1422 | 1423 | case 12: 1424 | _ref19 = _iterator16[_i16++]; 1425 | context$3$0.next = 19; 1426 | break; 1427 | 1428 | case 15: 1429 | _i16 = _iterator16.next(); 1430 | 1431 | if (!_i16.done) { 1432 | context$3$0.next = 18; 1433 | break; 1434 | } 1435 | 1436 | return context$3$0.abrupt('break', 31); 1437 | 1438 | case 18: 1439 | _ref19 = _i16.value; 1440 | 1441 | case 19: 1442 | group = _ref19; 1443 | 1444 | if (!resultTrans) { 1445 | context$3$0.next = 25; 1446 | break; 1447 | } 1448 | 1449 | context$3$0.next = 23; 1450 | return resultTrans(group.key, group.values); 1451 | 1452 | case 23: 1453 | context$3$0.next = 29; 1454 | break; 1455 | 1456 | case 25: 1457 | result = asEnumerable(group.values); 1458 | 1459 | result.key = group.key; 1460 | context$3$0.next = 29; 1461 | return result; 1462 | 1463 | case 29: 1464 | context$3$0.next = 9; 1465 | break; 1466 | 1467 | case 31: 1468 | case 'end': 1469 | return context$3$0.stop(); 1470 | } 1471 | }, callee$2$0, this); 1472 | })); 1473 | } else { 1474 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1475 | var seqMap, _iterator17, _isArray17, _i17, _ref20, x, key, val, _iterator18, _isArray18, _i18, _ref21, valSeq, result; 1476 | 1477 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1478 | while (1) switch (context$3$0.prev = context$3$0.next) { 1479 | case 0: 1480 | seqMap = new Map(); 1481 | _iterator17 = _this, _isArray17 = Array.isArray(_iterator17), _i17 = 0, _iterator17 = _isArray17 ? _iterator17 : _iterator17[Symbol.iterator](); 1482 | 1483 | case 2: 1484 | if (!_isArray17) { 1485 | context$3$0.next = 8; 1486 | break; 1487 | } 1488 | 1489 | if (!(_i17 >= _iterator17.length)) { 1490 | context$3$0.next = 5; 1491 | break; 1492 | } 1493 | 1494 | return context$3$0.abrupt('break', 19); 1495 | 1496 | case 5: 1497 | _ref20 = _iterator17[_i17++]; 1498 | context$3$0.next = 12; 1499 | break; 1500 | 1501 | case 8: 1502 | _i17 = _iterator17.next(); 1503 | 1504 | if (!_i17.done) { 1505 | context$3$0.next = 11; 1506 | break; 1507 | } 1508 | 1509 | return context$3$0.abrupt('break', 19); 1510 | 1511 | case 11: 1512 | _ref20 = _i17.value; 1513 | 1514 | case 12: 1515 | x = _ref20; 1516 | key = keySelector(x); 1517 | val = valueSelector(x); 1518 | 1519 | if (!seqMap.has(key)) { 1520 | seqMap.set(key, []); 1521 | } 1522 | seqMap.get(key).push(val); 1523 | 1524 | case 17: 1525 | context$3$0.next = 2; 1526 | break; 1527 | 1528 | case 19: 1529 | _iterator18 = seqMap, _isArray18 = Array.isArray(_iterator18), _i18 = 0, _iterator18 = _isArray18 ? _iterator18 : _iterator18[Symbol.iterator](); 1530 | 1531 | case 20: 1532 | if (!_isArray18) { 1533 | context$3$0.next = 26; 1534 | break; 1535 | } 1536 | 1537 | if (!(_i18 >= _iterator18.length)) { 1538 | context$3$0.next = 23; 1539 | break; 1540 | } 1541 | 1542 | return context$3$0.abrupt('break', 43); 1543 | 1544 | case 23: 1545 | _ref21 = _iterator18[_i18++]; 1546 | context$3$0.next = 30; 1547 | break; 1548 | 1549 | case 26: 1550 | _i18 = _iterator18.next(); 1551 | 1552 | if (!_i18.done) { 1553 | context$3$0.next = 29; 1554 | break; 1555 | } 1556 | 1557 | return context$3$0.abrupt('break', 43); 1558 | 1559 | case 29: 1560 | _ref21 = _i18.value; 1561 | 1562 | case 30: 1563 | key = _ref21[0]; 1564 | valSeq = _ref21[1]; 1565 | 1566 | if (!resultTrans) { 1567 | context$3$0.next = 37; 1568 | break; 1569 | } 1570 | 1571 | context$3$0.next = 35; 1572 | return resultTrans(key, valSeq); 1573 | 1574 | case 35: 1575 | context$3$0.next = 41; 1576 | break; 1577 | 1578 | case 37: 1579 | result = asEnumerable(valSeq); 1580 | 1581 | result.key = key; 1582 | context$3$0.next = 41; 1583 | return result; 1584 | 1585 | case 41: 1586 | context$3$0.next = 20; 1587 | break; 1588 | 1589 | case 43: 1590 | case 'end': 1591 | return context$3$0.stop(); 1592 | } 1593 | }, callee$2$0, this); 1594 | })); 1595 | } 1596 | }; 1597 | 1598 | Enumerable.prototype.orderBy = function orderBy(keySelector) { 1599 | var comp = arguments.length <= 1 || arguments[1] === undefined ? defaultComp : arguments[1]; 1600 | 1601 | var _this = this; 1602 | var result = new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1603 | var iter; 1604 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1605 | while (1) switch (context$3$0.prev = context$3$0.next) { 1606 | case 0: 1607 | iter = orderByImpl(_this, this._orderByOptions); 1608 | return context$3$0.delegateYield(iter, 't0', 2); 1609 | 1610 | case 2: 1611 | case 'end': 1612 | return context$3$0.stop(); 1613 | } 1614 | }, callee$2$0, this); 1615 | })); 1616 | result._orderByOptions = [createSortOption(keySelector, comp)]; 1617 | return result; 1618 | }; 1619 | 1620 | Enumerable.prototype.orderByDescending = function orderByDescending(keySelector) { 1621 | var comp = arguments.length <= 1 || arguments[1] === undefined ? defaultComp : arguments[1]; 1622 | 1623 | return this.orderBy(keySelector, function (x, y) { 1624 | return -comp(x, y); 1625 | }); 1626 | }; 1627 | 1628 | Enumerable.prototype.thenBy = function thenBy(keySelector) { 1629 | var comp = arguments.length <= 1 || arguments[1] === undefined ? defaultComp : arguments[1]; 1630 | 1631 | if (!this._orderByOptions) { 1632 | throw 'thenBy() must follow an orderBy()/thenBy().'; 1633 | } 1634 | 1635 | var result = this._clone(); 1636 | result._orderByOptions.push(createSortOption(keySelector, comp)); 1637 | return result; 1638 | }; 1639 | 1640 | Enumerable.prototype.thenByDescending = function thenByDescending(keySelector) { 1641 | var comp = arguments.length <= 1 || arguments[1] === undefined ? defaultComp : arguments[1]; 1642 | 1643 | return this.thenBy(keySelector, function (x, y) { 1644 | return -comp(x, y); 1645 | }); 1646 | }; 1647 | 1648 | Enumerable.prototype.join = function join(other) { 1649 | var thisKeySelector = arguments.length <= 1 || arguments[1] === undefined ? defaultSelector : arguments[1]; 1650 | var otherKeySelector = arguments.length <= 2 || arguments[2] === undefined ? defaultSelector : arguments[2]; 1651 | var resultTrans = arguments.length <= 3 || arguments[3] === undefined ? function (x, y) { 1652 | return [x, y]; 1653 | } : arguments[3]; 1654 | var equal = arguments.length <= 4 || arguments[4] === undefined ? defaultEqual : arguments[4]; 1655 | 1656 | return joinImpl(this, other, thisKeySelector, otherKeySelector, resultTrans, equal, false); 1657 | }; 1658 | 1659 | Enumerable.prototype.groupJoin = function groupJoin(other) { 1660 | var thisKeySelector = arguments.length <= 1 || arguments[1] === undefined ? defaultSelector : arguments[1]; 1661 | var otherKeySelector = arguments.length <= 2 || arguments[2] === undefined ? defaultSelector : arguments[2]; 1662 | var resultTrans = arguments.length <= 3 || arguments[3] === undefined ? function (x, ySeq) { 1663 | return [x, ySeq]; 1664 | } : arguments[3]; 1665 | var equal = arguments.length <= 4 || arguments[4] === undefined ? defaultEqual : arguments[4]; 1666 | 1667 | return joinImpl(this, other, thisKeySelector, otherKeySelector, resultTrans, equal, true); 1668 | }; 1669 | 1670 | Enumerable.prototype.zip = function zip(other) { 1671 | var resultTrans = arguments.length <= 1 || arguments[1] === undefined ? function (x, y) { 1672 | return [x, y]; 1673 | } : arguments[1]; 1674 | 1675 | if (!other) { 1676 | throw 'must provide @other'; 1677 | } 1678 | var _this = this; 1679 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1680 | var iter1, iter2, elem1, elem2; 1681 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1682 | while (1) switch (context$3$0.prev = context$3$0.next) { 1683 | case 0: 1684 | iter1 = _this[Symbol.iterator](); 1685 | iter2 = other[Symbol.iterator](); 1686 | elem1 = undefined, elem2 = undefined; 1687 | 1688 | case 3: 1689 | if (!(!(elem1 = iter1.next()).done && !(elem2 = iter2.next()).done)) { 1690 | context$3$0.next = 8; 1691 | break; 1692 | } 1693 | 1694 | context$3$0.next = 6; 1695 | return resultTrans(elem1.value, elem2.value); 1696 | 1697 | case 6: 1698 | context$3$0.next = 3; 1699 | break; 1700 | 1701 | case 8: 1702 | case 'end': 1703 | return context$3$0.stop(); 1704 | } 1705 | }, callee$2$0, this); 1706 | })); 1707 | }; 1708 | 1709 | Enumerable.prototype.concat = function concat(other) { 1710 | if (!other) { 1711 | throw 'must provide @other'; 1712 | } 1713 | var _this = this; 1714 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1715 | var _iterator19, _isArray19, _i19, _ref22, x, _iterator20, _isArray20, _i20, _ref23, y; 1716 | 1717 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1718 | while (1) switch (context$3$0.prev = context$3$0.next) { 1719 | case 0: 1720 | _iterator19 = _this, _isArray19 = Array.isArray(_iterator19), _i19 = 0, _iterator19 = _isArray19 ? _iterator19 : _iterator19[Symbol.iterator](); 1721 | 1722 | case 1: 1723 | if (!_isArray19) { 1724 | context$3$0.next = 7; 1725 | break; 1726 | } 1727 | 1728 | if (!(_i19 >= _iterator19.length)) { 1729 | context$3$0.next = 4; 1730 | break; 1731 | } 1732 | 1733 | return context$3$0.abrupt('break', 16); 1734 | 1735 | case 4: 1736 | _ref22 = _iterator19[_i19++]; 1737 | context$3$0.next = 11; 1738 | break; 1739 | 1740 | case 7: 1741 | _i19 = _iterator19.next(); 1742 | 1743 | if (!_i19.done) { 1744 | context$3$0.next = 10; 1745 | break; 1746 | } 1747 | 1748 | return context$3$0.abrupt('break', 16); 1749 | 1750 | case 10: 1751 | _ref22 = _i19.value; 1752 | 1753 | case 11: 1754 | x = _ref22; 1755 | context$3$0.next = 14; 1756 | return x; 1757 | 1758 | case 14: 1759 | context$3$0.next = 1; 1760 | break; 1761 | 1762 | case 16: 1763 | _iterator20 = other, _isArray20 = Array.isArray(_iterator20), _i20 = 0, _iterator20 = _isArray20 ? _iterator20 : _iterator20[Symbol.iterator](); 1764 | 1765 | case 17: 1766 | if (!_isArray20) { 1767 | context$3$0.next = 23; 1768 | break; 1769 | } 1770 | 1771 | if (!(_i20 >= _iterator20.length)) { 1772 | context$3$0.next = 20; 1773 | break; 1774 | } 1775 | 1776 | return context$3$0.abrupt('break', 32); 1777 | 1778 | case 20: 1779 | _ref23 = _iterator20[_i20++]; 1780 | context$3$0.next = 27; 1781 | break; 1782 | 1783 | case 23: 1784 | _i20 = _iterator20.next(); 1785 | 1786 | if (!_i20.done) { 1787 | context$3$0.next = 26; 1788 | break; 1789 | } 1790 | 1791 | return context$3$0.abrupt('break', 32); 1792 | 1793 | case 26: 1794 | _ref23 = _i20.value; 1795 | 1796 | case 27: 1797 | y = _ref23; 1798 | context$3$0.next = 30; 1799 | return y; 1800 | 1801 | case 30: 1802 | context$3$0.next = 17; 1803 | break; 1804 | 1805 | case 32: 1806 | case 'end': 1807 | return context$3$0.stop(); 1808 | } 1809 | }, callee$2$0, this); 1810 | })); 1811 | }; 1812 | 1813 | Enumerable.prototype.otherThan = function otherThan(other, equal) { 1814 | var _this3 = this; 1815 | 1816 | if (!other) { 1817 | throw 'must provide @other'; 1818 | } 1819 | if (equal) { 1820 | var _ret3 = (function () { 1821 | var otherCache = asEnumerable(other).distinct().eval(); 1822 | return { 1823 | v: _this3.where(function (x) { 1824 | return otherCache.all(function (y) { 1825 | return !equal(x, y); 1826 | }); 1827 | }) 1828 | }; 1829 | })(); 1830 | 1831 | if (typeof _ret3 === 'object') return _ret3.v; 1832 | } else { 1833 | var _ret4 = (function () { 1834 | var otherSet = undefined; 1835 | return { 1836 | v: _this3.where(function (x) { 1837 | if (!otherSet) { 1838 | otherSet = asEnumerable(other).toSet(); 1839 | } 1840 | return !otherSet.has(x); 1841 | }) 1842 | }; 1843 | })(); 1844 | 1845 | if (typeof _ret4 === 'object') return _ret4.v; 1846 | } 1847 | }; 1848 | 1849 | Enumerable.prototype.distinct = function distinct(equal) { 1850 | var _this = this; 1851 | 1852 | if (equal) { 1853 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1854 | var generated, _loop2, _iterator21, _isArray21, _i21, _ref24, _ret5; 1855 | 1856 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1857 | var _this4 = this; 1858 | 1859 | while (1) switch (context$3$0.prev = context$3$0.next) { 1860 | case 0: 1861 | generated = []; 1862 | _loop2 = regeneratorRuntime.mark(function callee$3$0() { 1863 | var x; 1864 | return regeneratorRuntime.wrap(function callee$3$0$(context$4$0) { 1865 | while (1) switch (context$4$0.prev = context$4$0.next) { 1866 | case 0: 1867 | if (!_isArray21) { 1868 | context$4$0.next = 6; 1869 | break; 1870 | } 1871 | 1872 | if (!(_i21 >= _iterator21.length)) { 1873 | context$4$0.next = 3; 1874 | break; 1875 | } 1876 | 1877 | return context$4$0.abrupt('return', 'break'); 1878 | 1879 | case 3: 1880 | _ref24 = _iterator21[_i21++]; 1881 | context$4$0.next = 10; 1882 | break; 1883 | 1884 | case 6: 1885 | _i21 = _iterator21.next(); 1886 | 1887 | if (!_i21.done) { 1888 | context$4$0.next = 9; 1889 | break; 1890 | } 1891 | 1892 | return context$4$0.abrupt('return', 'break'); 1893 | 1894 | case 9: 1895 | _ref24 = _i21.value; 1896 | 1897 | case 10: 1898 | x = _ref24; 1899 | 1900 | if (!asEnumerable(generated).all(function (y) { 1901 | return !equal(x, y); 1902 | })) { 1903 | context$4$0.next = 15; 1904 | break; 1905 | } 1906 | 1907 | generated.push(x); 1908 | context$4$0.next = 15; 1909 | return x; 1910 | 1911 | case 15: 1912 | case 'end': 1913 | return context$4$0.stop(); 1914 | } 1915 | }, callee$3$0, _this4); 1916 | }); 1917 | _iterator21 = _this, _isArray21 = Array.isArray(_iterator21), _i21 = 0, _iterator21 = _isArray21 ? _iterator21 : _iterator21[Symbol.iterator](); 1918 | 1919 | case 3: 1920 | return context$3$0.delegateYield(_loop2(), 't0', 4); 1921 | 1922 | case 4: 1923 | _ret5 = context$3$0.t0; 1924 | 1925 | if (!(_ret5 === 'break')) { 1926 | context$3$0.next = 7; 1927 | break; 1928 | } 1929 | 1930 | return context$3$0.abrupt('break', 9); 1931 | 1932 | case 7: 1933 | context$3$0.next = 3; 1934 | break; 1935 | 1936 | case 9: 1937 | case 'end': 1938 | return context$3$0.stop(); 1939 | } 1940 | }, callee$2$0, this); 1941 | })); 1942 | } else { 1943 | return new Enumerable(regeneratorRuntime.mark(function callee$2$0() { 1944 | var valSet, _iterator22, _isArray22, _i22, _ref25, x; 1945 | 1946 | return regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { 1947 | while (1) switch (context$3$0.prev = context$3$0.next) { 1948 | case 0: 1949 | valSet = new Set(); 1950 | _iterator22 = _this, _isArray22 = Array.isArray(_iterator22), _i22 = 0, _iterator22 = _isArray22 ? _iterator22 : _iterator22[Symbol.iterator](); 1951 | 1952 | case 2: 1953 | if (!_isArray22) { 1954 | context$3$0.next = 8; 1955 | break; 1956 | } 1957 | 1958 | if (!(_i22 >= _iterator22.length)) { 1959 | context$3$0.next = 5; 1960 | break; 1961 | } 1962 | 1963 | return context$3$0.abrupt('break', 18); 1964 | 1965 | case 5: 1966 | _ref25 = _iterator22[_i22++]; 1967 | context$3$0.next = 12; 1968 | break; 1969 | 1970 | case 8: 1971 | _i22 = _iterator22.next(); 1972 | 1973 | if (!_i22.done) { 1974 | context$3$0.next = 11; 1975 | break; 1976 | } 1977 | 1978 | return context$3$0.abrupt('break', 18); 1979 | 1980 | case 11: 1981 | _ref25 = _i22.value; 1982 | 1983 | case 12: 1984 | x = _ref25; 1985 | 1986 | if (!(valSet.size !== valSet.add(x).size)) { 1987 | context$3$0.next = 16; 1988 | break; 1989 | } 1990 | 1991 | context$3$0.next = 16; 1992 | return x; 1993 | 1994 | case 16: 1995 | context$3$0.next = 2; 1996 | break; 1997 | 1998 | case 18: 1999 | case 'end': 2000 | return context$3$0.stop(); 2001 | } 2002 | }, callee$2$0, this); 2003 | })); 2004 | } 2005 | }; 2006 | 2007 | Enumerable.prototype.union = function union(other, equal) { 2008 | if (!other) { 2009 | throw 'must provide @other'; 2010 | } 2011 | return this.concat(other).distinct(equal); 2012 | }; 2013 | 2014 | Enumerable.prototype.intersect = function intersect(other, equal) { 2015 | var _this5 = this; 2016 | 2017 | if (!other) { 2018 | throw 'must provide @other'; 2019 | } 2020 | if (equal) { 2021 | var _ret6 = (function () { 2022 | var otherCache = asEnumerable(asEnumerable(other).toArray()); 2023 | return { 2024 | v: _this5.where(function (x) { 2025 | return otherCache.any(function (y) { 2026 | return equal(x, y); 2027 | }); 2028 | }) 2029 | }; 2030 | })(); 2031 | 2032 | if (typeof _ret6 === 'object') return _ret6.v; 2033 | } else { 2034 | var _ret7 = (function () { 2035 | var otherSet = undefined; 2036 | return { 2037 | v: _this5.where(function (x) { 2038 | if (!otherSet) { 2039 | otherSet = asEnumerable(other).toSet(); 2040 | } 2041 | return otherSet.has(x); 2042 | }).distinct() 2043 | }; 2044 | })(); 2045 | 2046 | if (typeof _ret7 === 'object') return _ret7.v; 2047 | } 2048 | }; 2049 | 2050 | Enumerable.prototype.except = function except(other, equal) { 2051 | if (!other) { 2052 | throw 'must provide @other'; 2053 | } 2054 | return this.distinct().otherThan(other, equal); 2055 | }; 2056 | 2057 | Enumerable.prototype.all = function all(pred) { 2058 | if (typeof pred !== 'function') { 2059 | throw 'must provide @pred'; 2060 | } 2061 | var index = 0; 2062 | for (var _iterator23 = this, _isArray23 = Array.isArray(_iterator23), _i23 = 0, _iterator23 = _isArray23 ? _iterator23 : _iterator23[Symbol.iterator]();;) { 2063 | var _ref26; 2064 | 2065 | if (_isArray23) { 2066 | if (_i23 >= _iterator23.length) break; 2067 | _ref26 = _iterator23[_i23++]; 2068 | } else { 2069 | _i23 = _iterator23.next(); 2070 | if (_i23.done) break; 2071 | _ref26 = _i23.value; 2072 | } 2073 | 2074 | var x = _ref26; 2075 | 2076 | if (!pred(x, index++)) return false; 2077 | } 2078 | return true; 2079 | }; 2080 | 2081 | Enumerable.prototype.any = function any() { 2082 | var pred = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2083 | return true; 2084 | } : arguments[0]; 2085 | 2086 | var index = 0; 2087 | for (var _iterator24 = this, _isArray24 = Array.isArray(_iterator24), _i24 = 0, _iterator24 = _isArray24 ? _iterator24 : _iterator24[Symbol.iterator]();;) { 2088 | var _ref27; 2089 | 2090 | if (_isArray24) { 2091 | if (_i24 >= _iterator24.length) break; 2092 | _ref27 = _iterator24[_i24++]; 2093 | } else { 2094 | _i24 = _iterator24.next(); 2095 | if (_i24.done) break; 2096 | _ref27 = _i24.value; 2097 | } 2098 | 2099 | var x = _ref27; 2100 | 2101 | if (pred(x, index++)) return true; 2102 | } 2103 | return false; 2104 | }; 2105 | 2106 | Enumerable.prototype.singleOrDefault = function singleOrDefault(pred, throwWhenNotFound) { 2107 | if (pred === undefined) pred = function (x) { 2108 | return true; 2109 | }; 2110 | 2111 | var chosen = undefined; 2112 | var alreadyMet = false; 2113 | var index = 0; 2114 | for (var _iterator25 = this, _isArray25 = Array.isArray(_iterator25), _i25 = 0, _iterator25 = _isArray25 ? _iterator25 : _iterator25[Symbol.iterator]();;) { 2115 | var _ref28; 2116 | 2117 | if (_isArray25) { 2118 | if (_i25 >= _iterator25.length) break; 2119 | _ref28 = _iterator25[_i25++]; 2120 | } else { 2121 | _i25 = _iterator25.next(); 2122 | if (_i25.done) break; 2123 | _ref28 = _i25.value; 2124 | } 2125 | 2126 | var x = _ref28; 2127 | 2128 | if (pred(x, index++)) { 2129 | if (alreadyMet) { 2130 | throw 'more than one element match.'; 2131 | } else { 2132 | alreadyMet = true; 2133 | chosen = x; 2134 | } 2135 | } 2136 | } 2137 | if (throwWhenNotFound && !alreadyMet) { 2138 | throw 'no element found for specified @pred.'; 2139 | } 2140 | return chosen; 2141 | }; 2142 | 2143 | Enumerable.prototype.single = function single() { 2144 | var pred = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2145 | return true; 2146 | } : arguments[0]; 2147 | 2148 | return this.singleOrDefault(pred, true); 2149 | }; 2150 | 2151 | Enumerable.prototype.count = function count(pred) { 2152 | if (!pred && this._isBaseObjectRandomlyAccessible()) { 2153 | return this._baseObject.length; 2154 | } 2155 | 2156 | pred = pred || function (x) { 2157 | return true; 2158 | }; 2159 | var result = 0; 2160 | for (var _iterator26 = this, _isArray26 = Array.isArray(_iterator26), _i26 = 0, _iterator26 = _isArray26 ? _iterator26 : _iterator26[Symbol.iterator]();;) { 2161 | var _ref29; 2162 | 2163 | if (_isArray26) { 2164 | if (_i26 >= _iterator26.length) break; 2165 | _ref29 = _iterator26[_i26++]; 2166 | } else { 2167 | _i26 = _iterator26.next(); 2168 | if (_i26.done) break; 2169 | _ref29 = _i26.value; 2170 | } 2171 | 2172 | var x = _ref29; 2173 | 2174 | if (pred(x)) { 2175 | result++; 2176 | } 2177 | } 2178 | return result; 2179 | }; 2180 | 2181 | Enumerable.prototype.contains = function contains(val) { 2182 | var comp = arguments.length <= 1 || arguments[1] === undefined ? function (x, y) { 2183 | return x === y; 2184 | } : arguments[1]; 2185 | 2186 | return this.any(function (x) { 2187 | return comp(x, val); 2188 | }); 2189 | }; 2190 | 2191 | Enumerable.prototype.elementAtOrDefault = function elementAtOrDefault(index, throwWhenNotFound) { 2192 | if (!Number.isInteger(index)) { 2193 | throw '@index must be an integer'; 2194 | } 2195 | 2196 | if (this._isBaseObjectRandomlyAccessible()) { 2197 | if (throwWhenNotFound && (index < 0 || index >= this._baseObject.length)) { 2198 | throw 'No element found at specified index.'; 2199 | } 2200 | return this._baseObject[index]; 2201 | } 2202 | 2203 | var currentIndex = 0; 2204 | for (var _iterator27 = this, _isArray27 = Array.isArray(_iterator27), _i27 = 0, _iterator27 = _isArray27 ? _iterator27 : _iterator27[Symbol.iterator]();;) { 2205 | var _ref30; 2206 | 2207 | if (_isArray27) { 2208 | if (_i27 >= _iterator27.length) break; 2209 | _ref30 = _iterator27[_i27++]; 2210 | } else { 2211 | _i27 = _iterator27.next(); 2212 | if (_i27.done) break; 2213 | _ref30 = _i27.value; 2214 | } 2215 | 2216 | var x = _ref30; 2217 | 2218 | if (currentIndex++ === index) { 2219 | return x; 2220 | } 2221 | } 2222 | if (throwWhenNotFound) { 2223 | throw 'No element found at specified index.'; 2224 | } 2225 | }; 2226 | 2227 | Enumerable.prototype.elementAt = function elementAt(index) { 2228 | return this.elementAtOrDefault(index, true); 2229 | }; 2230 | 2231 | Enumerable.prototype.firstOrDefault = function firstOrDefault(pred, throwWhenNotFound) { 2232 | if (pred === undefined) pred = function (x) { 2233 | return true; 2234 | }; 2235 | 2236 | var index = 0; 2237 | for (var _iterator28 = this, _isArray28 = Array.isArray(_iterator28), _i28 = 0, _iterator28 = _isArray28 ? _iterator28 : _iterator28[Symbol.iterator]();;) { 2238 | var _ref31; 2239 | 2240 | if (_isArray28) { 2241 | if (_i28 >= _iterator28.length) break; 2242 | _ref31 = _iterator28[_i28++]; 2243 | } else { 2244 | _i28 = _iterator28.next(); 2245 | if (_i28.done) break; 2246 | _ref31 = _i28.value; 2247 | } 2248 | 2249 | var x = _ref31; 2250 | 2251 | if (pred(x, index++)) { 2252 | return x; 2253 | } 2254 | } 2255 | if (throwWhenNotFound) { 2256 | throw 'no elment found for specified @pred'; 2257 | } 2258 | }; 2259 | 2260 | Enumerable.prototype.first = function first() { 2261 | var pred = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2262 | return true; 2263 | } : arguments[0]; 2264 | 2265 | return this.firstOrDefault(pred, true); 2266 | }; 2267 | 2268 | Enumerable.prototype.lastOrDefault = function lastOrDefault(pred, throwWhenNotFound) { 2269 | var isDefaultPred = !pred; 2270 | pred = pred || function (x) { 2271 | return true; 2272 | }; 2273 | 2274 | if (this._isBaseObjectRandomlyAccessible()) { 2275 | var index = this._baseObject.length; 2276 | while (index-- > 0) { 2277 | var x = this._baseObject[index]; 2278 | if (pred(x, index)) { 2279 | return x; 2280 | } 2281 | } 2282 | if (throwWhenNotFound) { 2283 | throw 'no element found for specified @pred'; 2284 | } 2285 | return undefined; 2286 | } 2287 | 2288 | if (isDefaultPred) { 2289 | var buf = undefined; 2290 | var notEmpty = false; 2291 | for (var _iterator29 = this, _isArray29 = Array.isArray(_iterator29), _i29 = 0, _iterator29 = _isArray29 ? _iterator29 : _iterator29[Symbol.iterator]();;) { 2292 | var _ref32; 2293 | 2294 | if (_isArray29) { 2295 | if (_i29 >= _iterator29.length) break; 2296 | _ref32 = _iterator29[_i29++]; 2297 | } else { 2298 | _i29 = _iterator29.next(); 2299 | if (_i29.done) break; 2300 | _ref32 = _i29.value; 2301 | } 2302 | 2303 | var _x18 = _ref32; 2304 | 2305 | notEmpty = true; 2306 | buf = _x18; 2307 | } 2308 | if (throwWhenNotFound && !notEmpty) { 2309 | throw 'no element found for specified @pred'; 2310 | } 2311 | return buf; 2312 | } 2313 | 2314 | return this.reverse().firstOrDefault(pred, throwWhenNotFound); 2315 | }; 2316 | 2317 | Enumerable.prototype.last = function last(pred) { 2318 | return this.lastOrDefault(pred, true); 2319 | }; 2320 | 2321 | Enumerable.prototype.defaultIfEmpty = function defaultIfEmpty(val) { 2322 | return this.any() ? this : val === undefined ? empty() : asEnumerable([val]); 2323 | }; 2324 | 2325 | Enumerable.prototype.sequenceEqual = function sequenceEqual(other) { 2326 | var comp = arguments.length <= 1 || arguments[1] === undefined ? function (x, y) { 2327 | return x === y; 2328 | } : arguments[1]; 2329 | 2330 | var iter1 = this[Symbol.iterator](); 2331 | var iter2 = other[Symbol.iterator](); 2332 | var elem1 = undefined, 2333 | elem2 = undefined; 2334 | while (true) { 2335 | elem1 = iter1.next(); 2336 | elem2 = iter2.next(); 2337 | if (elem1.done || elem2.done) break; 2338 | if (!comp(elem1.value, elem2.value)) { 2339 | return false; 2340 | } 2341 | } 2342 | return elem1.done && elem2.done; 2343 | }; 2344 | 2345 | Enumerable.prototype._minMaxImpl = function _minMaxImpl(keySelector, comp) { 2346 | var minMaxKey = undefined; 2347 | var minMaxItem = undefined; 2348 | var index = 0; 2349 | for (var _iterator30 = this, _isArray30 = Array.isArray(_iterator30), _i30 = 0, _iterator30 = _isArray30 ? _iterator30 : _iterator30[Symbol.iterator]();;) { 2350 | var _ref33; 2351 | 2352 | if (_isArray30) { 2353 | if (_i30 >= _iterator30.length) break; 2354 | _ref33 = _iterator30[_i30++]; 2355 | } else { 2356 | _i30 = _iterator30.next(); 2357 | if (_i30.done) break; 2358 | _ref33 = _i30.value; 2359 | } 2360 | 2361 | var item = _ref33; 2362 | 2363 | var key = keySelector(item, index++); 2364 | if (minMaxKey === undefined) { 2365 | minMaxKey = key; 2366 | minMaxItem = item; 2367 | } else { 2368 | if (comp(key, minMaxKey)) { 2369 | minMaxKey = key; 2370 | minMaxItem = item; 2371 | } 2372 | } 2373 | } 2374 | return minMaxKey; 2375 | }; 2376 | 2377 | Enumerable.prototype.min = function min() { 2378 | var keySelector = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2379 | return x; 2380 | } : arguments[0]; 2381 | 2382 | return this._minMaxImpl(keySelector, function (x, y) { 2383 | return x < y; 2384 | }); 2385 | }; 2386 | 2387 | Enumerable.prototype.max = function max() { 2388 | var keySelector = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2389 | return x; 2390 | } : arguments[0]; 2391 | 2392 | return this._minMaxImpl(keySelector, function (x, y) { 2393 | return x > y; 2394 | }); 2395 | }; 2396 | 2397 | Enumerable.prototype.sum = function sum() { 2398 | var trans = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2399 | return x; 2400 | } : arguments[0]; 2401 | 2402 | var result = 0; 2403 | var index = 0; 2404 | for (var _iterator31 = this, _isArray31 = Array.isArray(_iterator31), _i31 = 0, _iterator31 = _isArray31 ? _iterator31 : _iterator31[Symbol.iterator]();;) { 2405 | var _ref34; 2406 | 2407 | if (_isArray31) { 2408 | if (_i31 >= _iterator31.length) break; 2409 | _ref34 = _iterator31[_i31++]; 2410 | } else { 2411 | _i31 = _iterator31.next(); 2412 | if (_i31.done) break; 2413 | _ref34 = _i31.value; 2414 | } 2415 | 2416 | var x = _ref34; 2417 | 2418 | result += trans(x, index++); 2419 | } 2420 | return result; 2421 | }; 2422 | 2423 | Enumerable.prototype.average = function average() { 2424 | var trans = arguments.length <= 0 || arguments[0] === undefined ? function (x) { 2425 | return x; 2426 | } : arguments[0]; 2427 | 2428 | var result = 0; 2429 | var count = 0; 2430 | var index = 0; 2431 | for (var _iterator32 = this, _isArray32 = Array.isArray(_iterator32), _i32 = 0, _iterator32 = _isArray32 ? _iterator32 : _iterator32[Symbol.iterator]();;) { 2432 | var _ref35; 2433 | 2434 | if (_isArray32) { 2435 | if (_i32 >= _iterator32.length) break; 2436 | _ref35 = _iterator32[_i32++]; 2437 | } else { 2438 | _i32 = _iterator32.next(); 2439 | if (_i32.done) break; 2440 | _ref35 = _i32.value; 2441 | } 2442 | 2443 | var x = _ref35; 2444 | 2445 | result += trans(x, index++); 2446 | count++; 2447 | } 2448 | return count === 0 ? 0 : result / count; 2449 | }; 2450 | 2451 | Enumerable.prototype.aggregate = function aggregate(seed, aggFunc, resultTrans) { 2452 | if (seed === undefined && aggFunc === undefined) { 2453 | throw 'must provide @seed only (treat as @aggFunc) or both @seed and @aggFunc with optional @resultTrans'; 2454 | } 2455 | 2456 | var iter = this[Symbol.iterator](); 2457 | 2458 | if (seed && !aggFunc && !resultTrans) { 2459 | aggFunc = seed; 2460 | seed = iter.next().value; 2461 | } 2462 | 2463 | resultTrans = resultTrans || function (x) { 2464 | return x; 2465 | }; 2466 | while (true) { 2467 | var elem = iter.next(); 2468 | if (elem.done) { 2469 | return resultTrans(seed); 2470 | } else { 2471 | seed = aggFunc(seed, elem.value); 2472 | } 2473 | } 2474 | }; 2475 | 2476 | Enumerable.prototype.eval = function _eval() { 2477 | return asEnumerable(this.toArray()); 2478 | }; 2479 | 2480 | Enumerable.prototype.toArray = function toArray() { 2481 | var result = []; 2482 | for (var _iterator33 = this, _isArray33 = Array.isArray(_iterator33), _i33 = 0, _iterator33 = _isArray33 ? _iterator33 : _iterator33[Symbol.iterator]();;) { 2483 | var _ref36; 2484 | 2485 | if (_isArray33) { 2486 | if (_i33 >= _iterator33.length) break; 2487 | _ref36 = _iterator33[_i33++]; 2488 | } else { 2489 | _i33 = _iterator33.next(); 2490 | if (_i33.done) break; 2491 | _ref36 = _i33.value; 2492 | } 2493 | 2494 | var x = _ref36; 2495 | 2496 | result.push(x); 2497 | } 2498 | return result; 2499 | }; 2500 | 2501 | Enumerable.prototype.toSet = function toSet() { 2502 | var result = new Set(); 2503 | for (var _iterator34 = this, _isArray34 = Array.isArray(_iterator34), _i34 = 0, _iterator34 = _isArray34 ? _iterator34 : _iterator34[Symbol.iterator]();;) { 2504 | var _ref37; 2505 | 2506 | if (_isArray34) { 2507 | if (_i34 >= _iterator34.length) break; 2508 | _ref37 = _iterator34[_i34++]; 2509 | } else { 2510 | _i34 = _iterator34.next(); 2511 | if (_i34.done) break; 2512 | _ref37 = _i34.value; 2513 | } 2514 | 2515 | var x = _ref37; 2516 | 2517 | result.add(x); 2518 | } 2519 | return result; 2520 | }; 2521 | 2522 | Enumerable.prototype.toMap = function toMap(keySelector, valueSelector) { 2523 | return new Map(this.select(function (x) { 2524 | return [keySelector(x), valueSelector(x)]; 2525 | })); 2526 | }; 2527 | 2528 | Enumerable.prototype.forEach = function forEach(op) { 2529 | if (typeof op !== 'function') { 2530 | throw '@op must be a function.'; 2531 | } 2532 | 2533 | for (var _iterator35 = this, _isArray35 = Array.isArray(_iterator35), _i35 = 0, _iterator35 = _isArray35 ? _iterator35 : _iterator35[Symbol.iterator]();;) { 2534 | var _ref38; 2535 | 2536 | if (_isArray35) { 2537 | if (_i35 >= _iterator35.length) break; 2538 | _ref38 = _iterator35[_i35++]; 2539 | } else { 2540 | _i35 = _iterator35.next(); 2541 | if (_i35.done) break; 2542 | _ref38 = _i35.value; 2543 | } 2544 | 2545 | var x = _ref38; 2546 | 2547 | op(x); 2548 | } 2549 | }; 2550 | 2551 | return Enumerable; 2552 | })(); 2553 | 2554 | function asEnumerable(obj) { 2555 | if (obj === undefined) { 2556 | obj = this; 2557 | } 2558 | 2559 | if (Enumerable.prototype.isPrototypeOf(obj)) { 2560 | return obj; 2561 | } 2562 | 2563 | if (!obj[Symbol.iterator]()) { 2564 | throw 'Object does not have a [iterator]. It cannot be used with asEnumerable()'; 2565 | } 2566 | return new Enumerable(regeneratorRuntime.mark(function callee$1$0() { 2567 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 2568 | while (1) switch (context$2$0.prev = context$2$0.next) { 2569 | case 0: 2570 | return context$2$0.delegateYield(obj[Symbol.iterator](), 't0', 1); 2571 | 2572 | case 1: 2573 | case 'end': 2574 | return context$2$0.stop(); 2575 | } 2576 | }, callee$1$0, this); 2577 | }), obj); 2578 | } 2579 | 2580 | ; 2581 | 2582 | function installAsEnumerable(constructor) { 2583 | if (constructor) { 2584 | constructor.prototype.asEnumerable = asEnumerable; 2585 | } else { 2586 | String.prototype.asEnumerable = Array.prototype.asEnumerable = asEnumerable; 2587 | } 2588 | } 2589 | 2590 | function range(start, count) { 2591 | return new Enumerable(regeneratorRuntime.mark(function callee$1$0() { 2592 | var i; 2593 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 2594 | while (1) switch (context$2$0.prev = context$2$0.next) { 2595 | case 0: 2596 | i = start; 2597 | 2598 | case 1: 2599 | if (!(i < start + count)) { 2600 | context$2$0.next = 7; 2601 | break; 2602 | } 2603 | 2604 | context$2$0.next = 4; 2605 | return i; 2606 | 2607 | case 4: 2608 | i++; 2609 | context$2$0.next = 1; 2610 | break; 2611 | 2612 | case 7: 2613 | case 'end': 2614 | return context$2$0.stop(); 2615 | } 2616 | }, callee$1$0, this); 2617 | })); 2618 | } 2619 | 2620 | function repeat(val, count) { 2621 | return new Enumerable(regeneratorRuntime.mark(function callee$1$0() { 2622 | var localCount; 2623 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 2624 | while (1) switch (context$2$0.prev = context$2$0.next) { 2625 | case 0: 2626 | localCount = count; 2627 | 2628 | case 1: 2629 | if (!(localCount-- > 0)) { 2630 | context$2$0.next = 6; 2631 | break; 2632 | } 2633 | 2634 | context$2$0.next = 4; 2635 | return val; 2636 | 2637 | case 4: 2638 | context$2$0.next = 1; 2639 | break; 2640 | 2641 | case 6: 2642 | case 'end': 2643 | return context$2$0.stop(); 2644 | } 2645 | }, callee$1$0, this); 2646 | })); 2647 | } 2648 | 2649 | function empty() { 2650 | return new Enumerable(regeneratorRuntime.mark(function callee$1$0() { 2651 | return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { 2652 | while (1) switch (context$2$0.prev = context$2$0.next) { 2653 | case 0: 2654 | case 'end': 2655 | return context$2$0.stop(); 2656 | } 2657 | }, callee$1$0, this); 2658 | })); 2659 | } 2660 | }); --------------------------------------------------------------------------------