├── .gitignore
├── npm.export.ts
├── .vscode
└── settings.json
├── tests.slim.html
├── tests.html
├── tests.performance.html
├── package.json
├── LICENSE
├── Release.txt
├── LInQer.extra.min.js
├── LInQer.slim.min.js
├── README.md
├── tsconfig.slim.json
├── tsconfig.json
├── tsconfig.all.json
├── tsconfig.extra.json
├── LInQer.GroupEnumerable.ts
├── tests.performance.js
├── qUnit
└── qunit-2.9.2.css
├── LInQer.extra.js.map
├── tests.slim.js
├── LInQer.slim.js.map
├── LInQer.OrderedEnumerable.ts
├── LInQer.extra.js
├── LInQer.min.js
├── LInQer.extra.ts
├── LInQer.Slim.ts
└── LInQer.Enumerable.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/npm.export.ts:
--------------------------------------------------------------------------------
1 | // export to NPM
2 | if (typeof(module) !== 'undefined') {
3 | module.exports = Linqer;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "es6-css-minify.hideButton": "auto",
3 | "es6-css-minify.js.mangle": true,
4 | "es6-css-minify.js.compress": true
5 | }
--------------------------------------------------------------------------------
/tests.slim.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Unit tests for LInQer (Slim)
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Unit tests for LInQer
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tests.performance.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Performance tests for LInQer
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@siderite/linqer",
3 | "version": "1.3.0",
4 | "description": "The C# Language Integrated Queries ported for Javascript for amazing performance",
5 | "main": "LInQer.all.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/Siderite/LInQer.git"
12 | },
13 | "keywords": [
14 | "LINQ",
15 | "Javascript",
16 | "ES6",
17 | "iterator",
18 | "generator",
19 | "Typescript"
20 | ],
21 | "author": "Siderite",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/Siderite/LInQer/issues"
25 | },
26 | "homepage": "https://siderite.dev/blog/linq-in-javascript-linqer",
27 | "dependencies": {
28 | "@types/node": "^13.7.0"
29 | },
30 | "devDependencies": {},
31 | "typings": "./LInQer.all.d.ts"
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Siderite
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Release.txt:
--------------------------------------------------------------------------------
1 | 2020-03-08 - 1.2.2
2 | - made typings work for Visual Studio Code for Node.js
3 | 2020-02-16 - 1.2.1
4 | - added comments to the code to better explain the mechanism
5 | - bugfix: canSeek was not set for reverse
6 | 2020-02-16 - 1.2.0
7 | - bugfix: lead had the wrong indexing function for elementAt
8 | - bugfix: ordered enumerables mistakenly reported being able to seek (elementAt)
9 | - performance improvements for toArray, reverse, shuffle, binarySearch
10 | - performance improvements for orderBy and sort in place
11 | 2020-02-14 - 1.1.5
12 | - fixed a few bugs
13 | - added slice
14 | - added splice and length, however Enumerable is not seen as an Array-like object, because length is a property not a field
15 | 2020-02-13 - 1.1.4
16 | - Simplified the partition stack code
17 | 2020-02-09 - 1.1.3
18 | - Added typings for Intellisense in TypeScript
19 | 2020-02-09 - 1.1.2
20 | - optimized Quicksort and orderBy even more
21 | 2020-02-09 - 1.1.1
22 | - separated the performance tests in their own files
23 | - small performance improvements
24 | - reverted the Quicksort algorithm to its original version
25 | - tried Timsort, it's pretty cool, but large and hard to control
26 | 2020-02-06 - 1.1.0
27 | - change of algorithm for sorting
28 | - useQuickSort and useBrowserSort now just set the sort mechanism, QuickSort is default
29 | - added static Enumerable.sort(arr,comparer) which uses Quicksort to sort an array in place
30 | 2020-02-02 - 1.0.7
31 | - library now exports Linqer as the module.exports object
32 | 2020-02-02 - 1.0.6
33 | - used case sensitive main entry point
34 | 2020-02-02 - 1.0.5
35 | - added Linqer.all.js for node.js use and used it as the main entry point
36 | - optimized sorting even more
37 | 2020-01-29 - 1.0.3
38 | - updated README
39 | - moved binarySearch on Enumerable (the user has the responsibility to have it ordered)
40 | 2020-01-27 - 1.0.2
41 | - added toList to return a seekable Enumerable
42 | - added lag and lead to return a join between the enumerable and itself with an offset
43 | - added padEnd and padStart to return enumerable of at least a specific length, filling the missing items with a given value
44 | 2020-01-23 - 1.0.1
45 | - added randomSample functionality
46 | 2020-01-22 - 1.0.0
47 | - official launch
48 |
--------------------------------------------------------------------------------
/LInQer.extra.min.js:
--------------------------------------------------------------------------------
1 | "use strict";var Linqer;!function(t){t.Enumerable.prototype.shuffle=function(){const e=this;const n=t.Enumerable.from((function*(){const t=e.toArray(),n=t.length;let o=0;for(;oe.count(),n},t.Enumerable.prototype.randomSample=function(e,n=Number.MAX_SAFE_INTEGER){let o=0;const r=[];if(t._ensureInternalTryGetAt(this),this._canSeek){const t=this.count();let o=0;for(o=0;o=n)break}return t.Enumerable.from(r)},t.Enumerable.prototype.distinctByHash=function(e){const n=this;return new t.Enumerable((function*(){const t=new Set;for(const o of n){const n=t.size;t.add(e(o)),n>1,s=n(o.elementAt(t),e);if(0==s)return t;s<0?r=t+1:a=t-1}return!1},t.Enumerable.prototype.lag=function(e,n){if(!e)throw new Error("offset has to be positive");if(e<0)throw new Error("offset has to be positive. Use .lead if you want to join with next items");n?t._ensureFunction(n):n=(t,e)=>[t,e];const o=this;t._ensureInternalTryGetAt(this);const r=new t.Enumerable((function*(){const t=Array(e);let r=0;for(const a of o){const o=r-e,s=o<0?void 0:t[o%e];yield n(a,s),t[r%e]=a,r++}}));return r._count=()=>{const t=o.count();return r._wasIterated||(r._wasIterated=o._wasIterated),t},o._canSeek&&(r._canSeek=!0,r._tryGetAt=t=>{const r=o._tryGetAt(t),a=o._tryGetAt(t-e);return r?{value:n(r.value,a?a.value:void 0)}:null}),r},t.Enumerable.prototype.lead=function(e,n){if(!e)throw new Error("offset has to be positive");if(e<0)throw new Error("offset has to be positive. Use .lag if you want to join with previous items");n?t._ensureFunction(n):n=(t,e)=>[t,e];const o=this;t._ensureInternalTryGetAt(this);const r=new t.Enumerable((function*(){const t=Array(e);let r=0;for(const a of o){const o=r-e;if(o>=0){const r=t[o%e];yield n(r,a)}t[r%e]=a,r++}for(let o=0;o{const t=o.count();return r._wasIterated||(r._wasIterated=o._wasIterated),t},o._canSeek&&(r._canSeek=!0,r._tryGetAt=t=>{const r=o._tryGetAt(t),a=o._tryGetAt(t+e);return r?{value:n(r.value,a?a.value:void 0)}:null}),r},t.Enumerable.prototype.padEnd=function(e,n){if(e<=0)throw new Error("minLength has to be positive.");let o;o="function"!=typeof n?t=>n:n;const r=this;t._ensureInternalTryGetAt(this);const a=new t.Enumerable((function*(){let t=0;for(const e of r)yield e,t++;for(;t{const t=Math.max(e,r.count());return a._wasIterated||(a._wasIterated=r._wasIterated),t},r._canSeek&&(a._canSeek=!0,a._tryGetAt=t=>{const n=r._tryGetAt(t);return n||(tn:n;const r=this;t._ensureInternalTryGetAt(r);const a=new t.Enumerable((function*(){const t=Array(e);let n=0;const a=r[Symbol.iterator]();let s=!1,u=!1;do{const r=a.next();if(u=!!r.done,u||(t[n]=r.value,n++),s&&!u)yield r.value;else if(u||n===e){for(let t=0;t{const t=Math.max(e,r.count());return a._wasIterated||(a._wasIterated=r._wasIterated),t},r._canSeek&&(a._canSeek=!0,a._tryGetAt=t=>{const n=r.count(),a=e-n;return a<=0?r._tryGetAt(t):t0,t._tryGetAt=t=>null,t._canSeek=!0,t}static range(t,n){const r=new e((function*(){for(let e=0;en,r._tryGetAt=e=>e>=0&&en,r._tryGetAt=e=>e>=0&&er.count()+i.count(),s(this),s(i),o._canSeek=r._canSeek&&i._canSeek,r._canSeek&&(o._tryGetAt=t=>r._tryGetAt(t)||i._tryGetAt(t-r.count())),o}count(){return i(this),this._count()}distinct(n=t.EqualityComparer.default){const r=this,o=n===t.EqualityComparer.default?function*(){const t=new Set;for(const e of r){const n=t.size;t.add(e),n0)&&(n.max=t),n.count++;return n}min(t){const e=this.stats(t);return 0===e.count?void 0:e.min}max(t){const e=this.stats(t);return 0===e.count?void 0:e.max}select(t){r(t);const n=this,o=new e((function*(){let e=0;for(const r of n)yield t(r,e),e++}));return i(this),o._count=this._count,s(n),o._canSeek=n._canSeek,o._tryGetAt=e=>{const r=n._tryGetAt(e);return r?{value:t(r.value)}:r},o}skip(t){const n=this,r=new e((function*(){let e=t;for(const t of n)e>0?e--:yield t}));return r._count=()=>Math.max(0,n.count()-t),s(this),r._canSeek=this._canSeek,r._tryGetAt=e=>n._tryGetAt(e+t),r}splice(t,e,...n){return this.take(t).concat(n).concat(this.skip(t+e))}sum(){const t=this.sumAndCount();return 0===t.count?void 0:t.sum}sumAndCount(){const t={count:0,sum:0};for(const e of this)t.sum=0===t.count?o(e):t.sum+o(e),t.count++;return t}take(t){const n=this,r=new e((function*(){let e=t;for(const t of n)if(e>0&&(yield t,e--),e<=0)break}));return r._count=()=>Math.min(t,n.count()),s(this),r._canSeek=n._canSeek,n._canSeek&&(r._tryGetAt=e=>e>=t?null:n._tryGetAt(e)),r}toArray(){var t;if(s(this),this._canSeek){const e=new Array(this.count());for(let n=0;ne._count())}const n=t._src;"function"==typeof n||"number"!=typeof n.length?"number"!=typeof n.size?t._count=()=>{let e=0;for(const n of t)e++;return e}:t._count=()=>n.size:t._count=()=>n.length}function s(t){if(t._tryGetAt)return;if(t._canSeek=!0,t._src instanceof e){const e=t._src;return s(e),t._tryGetAt=t=>e._tryGetAt(t),void(t._canSeek=e._canSeek)}if("string"==typeof t._src)return void(t._tryGetAt=e=>ee>=0&&e{let n=0;for(const r of t){if(e===n)return{value:r};n++}return null}):t._tryGetAt=t=>tt>e?1:tt==e,exact:(t,e)=>t===e}}(Linqer||(Linqer={}));
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MAJOR UPDATE: I've rewritten the entire thing into [linqer-ts](https://www.npmjs.com/package/@siderite/linqer-ts). Any improvements or updates will be on that project.
2 |
3 | # LInQer
4 | The C# Language Integrated Queries ported for Javascript for amazing performance
5 |
6 | [](https://badge.fury.io/js/%40siderite%2Flinqer) [](https://opensource.org/licenses/MIT)
7 |
8 | # Installation
9 | ```sh
10 | $ npm install @siderite/linqer
11 | ```
12 |
13 | # Quick start
14 | ```sh
15 | const source = ... an array or a generator function or anything that is iterable... ;
16 | const enumerable = Linqer.Enumerable.from(source); // now you can both iterate and use LINQ like functions
17 | const result = enumerable
18 | .where(item=>!!item.value) // like filter
19 | .select(item=>{ value: item.value, key: item.name }) // like map
20 | .groupBy(item=>item.key)
21 | .where(g=>g.length>10)
22 | .orderBy(g=>g.key)
23 | .selectMany()
24 | .skip(15)
25 | .take(5);
26 | for (const item of result) ...
27 | ```
28 | in Node.js you have to prepend:
29 | ```
30 | const Linqer = require('@siderite/linqer');
31 | ```
32 |
33 | in Typescript, use the .ts files directly or install @types/node and use require, I guess. I couldn't make it work for both TS and JS.
34 | I will try to make that happen in version 2, which will probably have a different file layout.
35 |
36 |
37 | # Licence
38 | MIT
39 |
40 | Array functions in Javascript create a new array for each operation, which is terribly wasteful. Using iterators and generator functions and objects, we can limit the operations to the items in the array that interest us, not all of them.
41 |
42 | # Blog post
43 | https://siderite.dev/blog/linq-in-javascript-linqer. Leave comments there or add Issues on GitHub for feedback and support.
44 |
45 | # Hosted
46 | Find it hosted on GitHub Pages and use it freely in your projects at:
47 | - https://siderite.github.io/LInQer/LInQer.min.js - main library
48 | - https://siderite.github.io/LInQer/LInQer.slim.min.js - only basic functionality
49 | - https://siderite.github.io/LInQer/LInQer.extra.min.js - extra functionality (needs main Linqer)
50 |
51 | # Reference
52 | Reference **Linqer.slim.js** for the basic methods:
53 | - from, empty, range, repeat - static on Linqer.Enumerable
54 | - length property - same as count, but throws error if the enumerable needs to be enumerated to get the length (no side effects)
55 | - concat
56 | - count
57 | - distinct
58 | - elementAt and elementAtOrDefault
59 | - first and firstOrDefault
60 | - last and lastOrDefault
61 | - min, max, stats (min, max and count)
62 | - select
63 | - skip and take
64 | - splice function - kind of useless, but it was an experiment to see if I can make Enumerable appear as an Array-like object
65 | - sum and sumAndCount (sum and count)
66 | - toArray
67 | - toList - similar to toArray, but returns a seekable Enumerable (itself if already seekable) that can do *count* and *elementAt* without iterating
68 | - where
69 |
70 | Reference **Linqer.js** for all of the original Enumerable methods, the ones in slim and then the following:
71 | - aggregate
72 | - all
73 | - any
74 | - append
75 | - average
76 | - asEnumerable
77 | - cast
78 | - contains
79 | - defaultIfEmpty - throws not implemented
80 | - except
81 | - intersect
82 | - join
83 | - groupBy
84 | - groupJoin
85 | - longCount
86 | - ofType
87 | - orderBy
88 | - orderByDescending
89 | - prepend
90 | - reverse
91 | - selectMany
92 | - sequenceEqual
93 | - single
94 | - singleOrDefault
95 | - skip - on an ordered enumerable
96 | - skipLast - on a regular or ordered enumerable
97 | - skipWhile
98 | - slice
99 | - take - on an ordered enumerable
100 | - takeLast - on a regular or ordered enumerable
101 | - takeWhile
102 | - thenBy - on an ordered enumerable
103 | - thenByDescending - on an ordered enumerable
104 | - toDictionary - throws not implemented
105 | - toLookup - throws not implemented
106 | - toMap
107 | - toObject
108 | - toHashSet - throws not implemented
109 | - toSet
110 | - union
111 | - zip
112 |
113 | Reference **Linqer.extra.js** (needs **Linqer.js**) for some additional methods:
114 | - shuffle - randomizes the enumerable
115 | - randomSample - implements random reservoir sampling of k items
116 | - distinctByHash - distinct based on a hashing function, not a comparer - faster
117 | - exceptByHash - except based on a hashing function, not a comparer - faster
118 | - intersectByHash - intersect based on a hashing function, not a comparer - faster
119 | - binarySearch - find the index of a value in a sorted enumerable by binary search
120 | - lag - joins each item of the enumerable with previous items from the same enumerable
121 | - lead - joins each item of the enumerable with next items from the same enumerable
122 | - padStart - pad enumerable at the start to a minimum length
123 | - padEnd - pad enumerable at the end to a minimum length
124 |
125 | # Original *Enumerable* .NET class
126 |
127 | The original C# class can be found here: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable .
128 |
129 | # Building the solution
130 |
131 | The library has been ported to Typescript. Run **build.bat** to create the .js and .map files from the .ts code.
--------------------------------------------------------------------------------
/tsconfig.slim.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "incremental": true, /* Enable incremental compilation */
5 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
6 | "module": "system", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
7 | // "lib": [], /* Specify library files to be included in the compilation. */
8 | // "allowJs": true, /* Allow javascript files to be compiled. */
9 | // "checkJs": true, /* Report errors in .js files. */
10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | "outFile": "./LInQer.slim.js", /* Concatenate and emit output to single file. */
15 | // "outDir": "./", /* Redirect output structure to the directory. */
16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
17 | // "composite": true, /* Enable project compilation */
18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
19 | // "removeComments": true, /* Do not emit comments to output. */
20 | // "noEmit": true, /* Do not emit outputs. */
21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
24 |
25 | /* Strict Type-Checking Options */
26 | "strict": true, /* Enable all strict type-checking options. */
27 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
28 | "strictNullChecks": true, /* Enable strict null checks. */
29 | "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
31 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
52 |
53 | /* Source Map Options */
54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
58 |
59 | /* Experimental Options */
60 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
61 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
62 |
63 | /* Advanced Options */
64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
65 | },
66 | "compileOnSave": true,
67 | "files": ["./LInQer.Slim.ts"]
68 | }
69 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "incremental": true, /* Enable incremental compilation */
5 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
6 | "module": "system", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
7 | // "lib": [], /* Specify library files to be included in the compilation. */
8 | // "allowJs": true, /* Allow javascript files to be compiled. */
9 | // "checkJs": true, /* Report errors in .js files. */
10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | "outFile": "./LInQer.js", /* Concatenate and emit output to single file. */
15 | // "outDir": "./", /* Redirect output structure to the directory. */
16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
17 | // "composite": true, /* Enable project compilation */
18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
19 | // "removeComments": true, /* Do not emit comments to output. */
20 | // "noEmit": true, /* Do not emit outputs. */
21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
24 |
25 | /* Strict Type-Checking Options */
26 | "strict": true, /* Enable all strict type-checking options. */
27 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
28 | "strictNullChecks": true, /* Enable strict null checks. */
29 | "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
31 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
52 |
53 | /* Source Map Options */
54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
58 |
59 | /* Experimental Options */
60 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
61 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
62 |
63 | /* Advanced Options */
64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
65 | },
66 | "compileOnSave": true,
67 | "files": ["./LInQer.Slim.ts","./LInQer.Enumerable.ts","./LInQer.GroupEnumerable.ts","./LInQer.OrderedEnumerable.ts","./npm.export.ts"]
68 | }
69 |
--------------------------------------------------------------------------------
/tsconfig.all.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "incremental": true, /* Enable incremental compilation */
5 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
6 | "module": "system", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
7 | // "lib": [], /* Specify library files to be included in the compilation. */
8 | // "allowJs": true, /* Allow javascript files to be compiled. */
9 | // "checkJs": true, /* Report errors in .js files. */
10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11 | "declaration": true, /* Generates corresponding '.d.ts' file. */
12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | "outFile": "./LInQer.all.js", /* Concatenate and emit output to single file. */
15 | // "outDir": "./", /* Redirect output structure to the directory. */
16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
17 | // "composite": true, /* Enable project compilation */
18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
19 | // "removeComments": true, /* Do not emit comments to output. */
20 | // "noEmit": true, /* Do not emit outputs. */
21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
24 |
25 | /* Strict Type-Checking Options */
26 | "strict": true, /* Enable all strict type-checking options. */
27 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
28 | "strictNullChecks": true, /* Enable strict null checks. */
29 | "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
31 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
52 |
53 | /* Source Map Options */
54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
58 |
59 | /* Experimental Options */
60 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
61 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
62 |
63 | /* Advanced Options */
64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
65 | },
66 | "compileOnSave": true,
67 | "files": ["./LInQer.Slim.ts","./LInQer.Enumerable.ts","./LInQer.GroupEnumerable.ts","./LInQer.OrderedEnumerable.ts","./LInQer.Extra.ts","./npm.export.ts"]
68 | }
69 |
--------------------------------------------------------------------------------
/tsconfig.extra.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "incremental": true, /* Enable incremental compilation */
5 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
6 | "module": "system", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
7 | // "lib": [], /* Specify library files to be included in the compilation. */
8 | // "allowJs": true, /* Allow javascript files to be compiled. */
9 | // "checkJs": true, /* Report errors in .js files. */
10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | // "outFile": "./LInQer.extra.js", /* Concatenate and emit output to single file. */
15 | // "outDir": "./", /* Redirect output structure to the directory. */
16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
17 | // "composite": true, /* Enable project compilation */
18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
19 | // "removeComments": true, /* Do not emit comments to output. */
20 | // "noEmit": true, /* Do not emit outputs. */
21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
24 |
25 | /* Strict Type-Checking Options */
26 | "strict": true, /* Enable all strict type-checking options. */
27 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
28 | "strictNullChecks": true, /* Enable strict null checks. */
29 | "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
31 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
52 |
53 | /* Source Map Options */
54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
58 |
59 | /* Experimental Options */
60 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
61 | "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
62 |
63 | /* Advanced Options */
64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
65 | },
66 | "compileOnSave": true,
67 | "files": ["./LInQer.extra.ts", "./LInQer.Slim.ts","./LInQer.Enumerable.ts","./LInQer.GroupEnumerable.ts","./LInQer.OrderedEnumerable.ts"]
68 | }
69 |
--------------------------------------------------------------------------------
/LInQer.GroupEnumerable.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | namespace Linqer {
4 |
5 | export interface Enumerable extends Iterable {
6 | /**
7 | * Groups the elements of a sequence.
8 | *
9 | * @param {ISelector} keySelector
10 | * @returns {Enumerable}
11 | * @memberof Enumerable
12 | */
13 | groupBy(keySelector: ISelector): Enumerable;
14 | /**
15 | * Correlates the elements of two sequences based on key equality and groups the results. A specified equalityComparer is used to compare keys.
16 | * WARNING: using the equality comparer will be slower
17 | *
18 | * @param {IterableType} iterable
19 | * @param {ISelector} innerKeySelector
20 | * @param {ISelector} outerKeySelector
21 | * @param {(item1: any, item2: any) => any} resultSelector
22 | * @param {IEqualityComparer} equalityComparer
23 | * @returns {Enumerable}
24 | * @memberof Enumerable
25 | */
26 | groupJoin(iterable: IterableType,
27 | innerKeySelector: ISelector,
28 | outerKeySelector: ISelector,
29 | resultSelector: (item1: any, item2: any) => any,
30 | equalityComparer: IEqualityComparer): Enumerable;
31 | /**
32 | * Correlates the elements of two sequences based on matching keys.
33 | * WARNING: using the equality comparer will be slower
34 | *
35 | * @param {IterableType} iterable
36 | * @param {ISelector} innerKeySelector
37 | * @param {ISelector} outerKeySelector
38 | * @param {(item1: any, item2: any) => any} resultSelector
39 | * @param {IEqualityComparer} equalityComparer
40 | * @returns {Enumerable}
41 | * @memberof Enumerable
42 | */
43 | join(iterable: IterableType,
44 | innerKeySelector: ISelector,
45 | outerKeySelector: ISelector,
46 | resultSelector: (item1: any, item2: any) => any,
47 | equalityComparer: IEqualityComparer): Enumerable;
48 | toLookup(): never;
49 | }
50 |
51 |
52 | /// Groups the elements of a sequence.
53 | Enumerable.prototype.groupBy = function (keySelector: ISelector): Enumerable {
54 | _ensureFunction(keySelector);
55 | const self: Enumerable = this;
56 | const gen = function* () {
57 | const groupMap = new Map();
58 | let index = 0;
59 | // iterate all items and group them in a Map
60 | for (const item of self) {
61 | const key = keySelector(item, index);
62 | const group = groupMap.get(key);
63 | if (group) {
64 | group.push(item);
65 | } else {
66 | groupMap.set(key, [item]);
67 | }
68 | index++;
69 | }
70 | // then yield a GroupEnumerable for each group
71 | for (const [key, items] of groupMap) {
72 | const group = new GroupEnumerable(items, key);
73 | yield group;
74 | }
75 | };
76 | const result = new Enumerable(gen);
77 | return result;
78 | }
79 |
80 | /// Correlates the elements of two sequences based on key equality and groups the results. A specified equalityComparer is used to compare keys.
81 | /// WARNING: using the equality comparer will be slower
82 | Enumerable.prototype.groupJoin = function (iterable: IterableType,
83 | innerKeySelector: ISelector,
84 | outerKeySelector: ISelector,
85 | resultSelector: (item1: any, item2: any) => any,
86 | equalityComparer: IEqualityComparer = EqualityComparer.default): Enumerable {
87 |
88 | const self: Enumerable = this;
89 | const gen = equalityComparer === EqualityComparer.default
90 | ? function* () {
91 | const lookup = new Enumerable(iterable)
92 | .groupBy(outerKeySelector)
93 | .toMap(g => g.key, g => g);
94 | let index = 0;
95 | for (const innerItem of self) {
96 | const arr = _toArray(lookup.get(innerKeySelector(innerItem, index)));
97 | yield resultSelector(innerItem, arr);
98 | index++;
99 | }
100 | }
101 | : function* () {
102 | let innerIndex = 0;
103 | for (const innerItem of self) {
104 | const arr = [];
105 | let outerIndex = 0;
106 | for (const outerItem of Enumerable.from(iterable)) {
107 | if (equalityComparer(innerKeySelector(innerItem, innerIndex), outerKeySelector(outerItem, outerIndex))) {
108 | arr.push(outerItem);
109 | }
110 | outerIndex++;
111 | }
112 | yield resultSelector(innerItem, arr);
113 | innerIndex++;
114 | }
115 | };
116 | return new Enumerable(gen);
117 | }
118 |
119 | /// Correlates the elements of two sequences based on matching keys.
120 | /// WARNING: using the equality comparer will be slower
121 | Enumerable.prototype.join = function (iterable: IterableType,
122 | innerKeySelector: ISelector,
123 | outerKeySelector: ISelector,
124 | resultSelector: (item1: any, item2: any) => any,
125 | equalityComparer: IEqualityComparer = EqualityComparer.default): Enumerable {
126 | const self: Enumerable = this;
127 | const gen = equalityComparer === EqualityComparer.default
128 | ? function* () {
129 | const lookup = new Enumerable(iterable)
130 | .groupBy(outerKeySelector)
131 | .toMap(g => g.key, g => g);
132 | let index = 0;
133 | for (const innerItem of self) {
134 | const group = lookup.get(innerKeySelector(innerItem, index));
135 | if (group) {
136 | for (const outerItem of group) {
137 | yield resultSelector(innerItem, outerItem);
138 | }
139 | }
140 | index++;
141 | }
142 | }
143 | : function* () {
144 | let innerIndex = 0;
145 | for (const innerItem of self) {
146 | let outerIndex = 0;
147 | for (const outerItem of Enumerable.from(iterable)) {
148 | if (equalityComparer(innerKeySelector(innerItem, innerIndex), outerKeySelector(outerItem, outerIndex))) {
149 | yield resultSelector(innerItem, outerItem);
150 | }
151 | outerIndex++;
152 | }
153 | innerIndex++;
154 | }
155 | };
156 | return new Enumerable(gen);
157 | }
158 |
159 |
160 | Enumerable.prototype.toLookup = function (): never {
161 | throw new Error('use groupBy instead of toLookup');
162 | }
163 |
164 | /**
165 | * An Enumerable that also exposes a group key
166 | *
167 | * @export
168 | * @class GroupEnumerable
169 | * @extends {Enumerable}
170 | */
171 | export class GroupEnumerable extends Enumerable {
172 | key: string;
173 | constructor(iterable: IterableType, key: string) {
174 | super(iterable);
175 | this.key = key;
176 | }
177 | }
178 | }
--------------------------------------------------------------------------------
/tests.performance.js:
--------------------------------------------------------------------------------
1 | Enumerable = Linqer.Enumerable;
2 | const largeNumber = 10000000;
3 |
4 | // performance tests
5 | QUnit.module('performance tests');
6 |
7 | QUnit.test( "Use only items that are required - standard", function( assert ) {
8 | const largeArray = Array(largeNumber).fill(10);
9 | const startTime = performance.now();
10 | const someCalculation = largeArray.filter(x=>x===10).map(x=>'v'+x).slice(100,110);
11 | Array.from(someCalculation);
12 | const endTime = performance.now();
13 | assert.ok(true,'Standard array use took '+(endTime-startTime)+'milliseconds');
14 | });
15 |
16 | QUnit.test( "Use only items that are required - Enumerable", function( assert ) {
17 | const largeArray = Array(largeNumber).fill(10);
18 | const startTime = performance.now();
19 | const someCalculation = Enumerable.from(largeArray).where(x=>x===10).select(x=>'v'+x).skip(100).take(10).toArray();
20 | Array.from(someCalculation);
21 | const endTime = performance.now();
22 | assert.ok(true,'Enumerable use took '+(endTime-startTime)+'milliseconds');
23 | });
24 |
25 | QUnit.test( "OrderBy performance random", function( assert ) {
26 | const size = largeNumber;
27 | const largeArray1 = Enumerable.range(1,size).shuffle().toArray();
28 |
29 | let startTime = performance.now();
30 | const result1 = Array.from(largeArray1).sort((i1,i2)=>i2-i1);
31 | let endTime = performance.now();
32 | assert.ok(true,'Order '+size+' items using Array.from then .sort took '+(endTime-startTime)+' milliseconds');
33 |
34 | startTime = performance.now();
35 | const result2 = Enumerable.from(largeArray1).orderBy(i=>size-i).useBrowserSort().toArray();
36 | endTime = performance.now();
37 | assert.ok(true,'Order '+size+' items using browser sort internally took '+(endTime-startTime)+' milliseconds');
38 |
39 | for (let i=0; isize-i).useQuickSort().toArray();
48 | endTime = performance.now();
49 | assert.ok(true,'Order '+size+' items using QuickSort took '+(endTime-startTime)+' milliseconds');
50 |
51 | for (let i=0; ii2-i1);
65 | let endTime = performance.now();
66 | assert.ok(true,'Order '+size+' items using Array.from then .sort took '+(endTime-startTime)+' milliseconds');
67 |
68 | startTime = performance.now();
69 | const result2 = Enumerable.from(largeArray1).orderBy(i=>size-i).useBrowserSort().toArray();
70 | endTime = performance.now();
71 | assert.ok(true,'Order '+size+' items using browser sort internally took '+(endTime-startTime)+' milliseconds');
72 |
73 | for (let i=0; isize-i).useQuickSort().toArray();
82 | endTime = performance.now();
83 | assert.ok(true,'Order '+size+' items using QuickSort took '+(endTime-startTime)+' milliseconds');
84 |
85 | for (let i=0; ii2-i1);
99 | let endTime = performance.now();
100 | assert.ok(true,'Order '+size+' items using Array.from then .sort took '+(endTime-startTime)+' milliseconds');
101 |
102 | startTime = performance.now();
103 | const result2 = Enumerable.from(largeArray1).orderBy(i=>size-i).useBrowserSort().toArray();
104 | endTime = performance.now();
105 | assert.ok(true,'Order '+size+' items using browser sort internally took '+(endTime-startTime)+' milliseconds');
106 |
107 | for (let i=0; isize-i).useQuickSort().toArray();
116 | endTime = performance.now();
117 | assert.ok(true,'Order '+size+' items using QuickSort took '+(endTime-startTime)+' milliseconds');
118 |
119 | for (let i=0; ii2-i1)).skip(100000).take(10000).toArray();
134 | let endTime = performance.now();
135 | assert.ok(true,'Order '+size+' items skip and take using .sort took '+(endTime-startTime)+' milliseconds');
136 |
137 | startTime = performance.now();
138 | let result2 = Enumerable.from(largeArray2).orderBy(i=>size-i).skip(100000).take(10000).toArray();
139 | endTime = performance.now();
140 | assert.ok(true,'Order '+size+' items skip and take using QuickSort took '+(endTime-startTime)+' milliseconds');
141 |
142 | for (let i=0; i * {
173 | box-sizing: border-box;
174 | max-height: 2.8em;
175 | display: block;
176 | padding: 0.4em;
177 | }
178 |
179 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > button {
180 | float: right;
181 | font: inherit;
182 | }
183 |
184 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > :last-child {
185 | /* insert padding to align with checkbox margins */
186 | padding-left: 3px;
187 | }
188 |
189 | #qunit-modulefilter-dropdown-list {
190 | max-height: 200px;
191 | overflow-y: auto;
192 | margin: 0;
193 | border-top: 2px groove threedhighlight;
194 | padding: 0.4em 0 0;
195 | font: smaller/1.5em sans-serif;
196 | }
197 |
198 | #qunit-modulefilter-dropdown-list li {
199 | white-space: nowrap;
200 | overflow: hidden;
201 | text-overflow: ellipsis;
202 | }
203 |
204 | #qunit-modulefilter-dropdown-list .clickable {
205 | display: block;
206 | padding-left: 0.15em;
207 | }
208 |
209 |
210 | /** Tests: Pass/Fail */
211 |
212 | #qunit-tests {
213 | list-style-position: inside;
214 | }
215 |
216 | #qunit-tests li {
217 | padding: 0.4em 1em 0.4em 1em;
218 | border-bottom: 1px solid #FFF;
219 | list-style-position: inside;
220 | }
221 |
222 | #qunit-tests > li {
223 | display: none;
224 | }
225 |
226 | #qunit-tests li.running,
227 | #qunit-tests li.pass,
228 | #qunit-tests li.fail,
229 | #qunit-tests li.skipped,
230 | #qunit-tests li.aborted {
231 | display: list-item;
232 | }
233 |
234 | #qunit-tests.hidepass {
235 | position: relative;
236 | }
237 |
238 | #qunit-tests.hidepass li.running,
239 | #qunit-tests.hidepass li.pass:not(.todo) {
240 | visibility: hidden;
241 | position: absolute;
242 | width: 0;
243 | height: 0;
244 | padding: 0;
245 | border: 0;
246 | margin: 0;
247 | }
248 |
249 | #qunit-tests li strong {
250 | cursor: pointer;
251 | }
252 |
253 | #qunit-tests li.skipped strong {
254 | cursor: default;
255 | }
256 |
257 | #qunit-tests li a {
258 | padding: 0.5em;
259 | color: #C2CCD1;
260 | text-decoration: none;
261 | }
262 |
263 | #qunit-tests li p a {
264 | padding: 0.25em;
265 | color: #6B6464;
266 | }
267 | #qunit-tests li a:hover,
268 | #qunit-tests li a:focus {
269 | color: #000;
270 | }
271 |
272 | #qunit-tests li .runtime {
273 | float: right;
274 | font-size: smaller;
275 | }
276 |
277 | .qunit-assert-list {
278 | margin-top: 0.5em;
279 | padding: 0.5em;
280 |
281 | background-color: #FFF;
282 |
283 | border-radius: 5px;
284 | }
285 |
286 | .qunit-source {
287 | margin: 0.6em 0 0.3em;
288 | }
289 |
290 | .qunit-collapsed {
291 | display: none;
292 | }
293 |
294 | #qunit-tests table {
295 | border-collapse: collapse;
296 | margin-top: 0.2em;
297 | }
298 |
299 | #qunit-tests th {
300 | text-align: right;
301 | vertical-align: top;
302 | padding: 0 0.5em 0 0;
303 | }
304 |
305 | #qunit-tests td {
306 | vertical-align: top;
307 | }
308 |
309 | #qunit-tests pre {
310 | margin: 0;
311 | white-space: pre-wrap;
312 | word-wrap: break-word;
313 | }
314 |
315 | #qunit-tests del {
316 | color: #374E0C;
317 | background-color: #E0F2BE;
318 | text-decoration: none;
319 | }
320 |
321 | #qunit-tests ins {
322 | color: #500;
323 | background-color: #FFCACA;
324 | text-decoration: none;
325 | }
326 |
327 | /*** Test Counts */
328 |
329 | #qunit-tests b.counts { color: #000; }
330 | #qunit-tests b.passed { color: #5E740B; }
331 | #qunit-tests b.failed { color: #710909; }
332 |
333 | #qunit-tests li li {
334 | padding: 5px;
335 | background-color: #FFF;
336 | border-bottom: none;
337 | list-style-position: inside;
338 | }
339 |
340 | /*** Passing Styles */
341 |
342 | #qunit-tests li li.pass {
343 | color: #3C510C;
344 | background-color: #FFF;
345 | border-left: 10px solid #C6E746;
346 | }
347 |
348 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
349 | #qunit-tests .pass .test-name { color: #366097; }
350 |
351 | #qunit-tests .pass .test-actual,
352 | #qunit-tests .pass .test-expected { color: #999; }
353 |
354 | #qunit-banner.qunit-pass { background-color: #C6E746; }
355 |
356 | /*** Failing Styles */
357 |
358 | #qunit-tests li li.fail {
359 | color: #710909;
360 | background-color: #FFF;
361 | border-left: 10px solid #EE5757;
362 | white-space: pre;
363 | }
364 |
365 | #qunit-tests > li:last-child {
366 | border-radius: 0 0 5px 5px;
367 | }
368 |
369 | #qunit-tests .fail { color: #000; background-color: #EE5757; }
370 | #qunit-tests .fail .test-name,
371 | #qunit-tests .fail .module-name { color: #000; }
372 |
373 | #qunit-tests .fail .test-actual { color: #EE5757; }
374 | #qunit-tests .fail .test-expected { color: #008000; }
375 |
376 | #qunit-banner.qunit-fail { background-color: #EE5757; }
377 |
378 |
379 | /*** Aborted tests */
380 | #qunit-tests .aborted { color: #000; background-color: orange; }
381 | /*** Skipped tests */
382 |
383 | #qunit-tests .skipped {
384 | background-color: #EBECE9;
385 | }
386 |
387 | #qunit-tests .qunit-todo-label,
388 | #qunit-tests .qunit-skipped-label {
389 | background-color: #F4FF77;
390 | display: inline-block;
391 | font-style: normal;
392 | color: #366097;
393 | line-height: 1.8em;
394 | padding: 0 0.5em;
395 | margin: -0.4em 0.4em -0.4em 0;
396 | }
397 |
398 | #qunit-tests .qunit-todo-label {
399 | background-color: #EEE;
400 | }
401 |
402 | /** Result */
403 |
404 | #qunit-testresult {
405 | color: #2B81AF;
406 | background-color: #D2E0E6;
407 |
408 | border-bottom: 1px solid #FFF;
409 | }
410 | #qunit-testresult .clearfix {
411 | height: 0;
412 | clear: both;
413 | }
414 | #qunit-testresult .module-name {
415 | font-weight: 700;
416 | }
417 | #qunit-testresult-display {
418 | padding: 0.5em 1em 0.5em 1em;
419 | width: 85%;
420 | float:left;
421 | }
422 | #qunit-testresult-controls {
423 | padding: 0.5em 1em 0.5em 1em;
424 | width: 10%;
425 | float:left;
426 | }
427 |
428 | /** Fixture */
429 |
430 | #qunit-fixture {
431 | position: absolute;
432 | top: -10000px;
433 | left: -10000px;
434 | width: 1000px;
435 | height: 1000px;
436 | }
437 |
--------------------------------------------------------------------------------
/LInQer.extra.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"LInQer.extra.js","sourceRoot":"","sources":["LInQer.extra.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/tests.slim.js:
--------------------------------------------------------------------------------
1 | Enumerable = Linqer.Enumerable;
2 |
3 | // object and method tests
4 | QUnit.module('object and method tests');
5 |
6 | QUnit.test("Enumerable.from with empty array", function (assert) {
7 | const enumerable = Enumerable.from([]);
8 | const result = [];
9 | for (const item of enumerable) result.push(item);
10 |
11 | assert.deepEqual(result, [], "Passed!");
12 | });
13 |
14 | QUnit.test("Enumerable.from with non empty array", function (assert) {
15 | const enumerable = Enumerable.from([1, 'a2', 3, null]);
16 | const result = [];
17 | for (const item of enumerable) result.push(item);
18 |
19 | assert.deepEqual(result, [1, 'a2', 3, null], "Passed!");
20 | });
21 |
22 | QUnit.test("Enumerable.from with generator function", function (assert) {
23 | function* gen() {
24 | yield 1;
25 | yield 'a2';
26 | yield 3;
27 | yield null;
28 | }
29 | const enumerable = Enumerable.from(gen());
30 | const result = [];
31 | for (const item of enumerable) result.push(item);
32 |
33 | assert.deepEqual(result, [1, 'a2', 3, null], "Passed!");
34 | });
35 |
36 | QUnit.test("Enumerable.concat", function (assert) {
37 | const result = Enumerable.from([1, 'xx2', 5]).concat([6, 7, 8]).toArray();
38 | assert.deepEqual(result, [1, 'xx2', 5, 6, 7, 8], "Passed!");
39 | });
40 |
41 | QUnit.test("Enumerable.count array", function (assert) {
42 | const result = Enumerable.from([1, 'xx2', 5]).count();
43 | assert.deepEqual(result, 3, "Passed!");
44 | });
45 | QUnit.test("Enumerable.count Map", function (assert) {
46 | const map = new Map();
47 | map.set(1, 2);
48 | map.set('a', '3');
49 | const result = Enumerable.from(map).count();
50 | assert.deepEqual(result, 2, "Passed!");
51 | });
52 | QUnit.test("Enumerable.count Set", function (assert) {
53 | const result = Enumerable.from(new Set().add(1).add(2).add(3).add(4)).count();
54 | assert.deepEqual(result, 4, "Passed!");
55 | });
56 | QUnit.test("Enumerable.count generator function", function (assert) {
57 | function* gen() {
58 | yield 'a';
59 | yield 1;
60 | }
61 | const result = Enumerable.from(gen()).count();
62 | assert.deepEqual(result, 2, "Passed!");
63 | });
64 |
65 | QUnit.test("Enumerable.distinct", function (assert) {
66 | const result = Enumerable.from([1, 2, 2, 3, '3']).distinct().toArray();
67 | assert.deepEqual(result, [1, 2, 3, '3'], "Passed!");
68 | });
69 | QUnit.test("Enumerable.distinct equality comparer", function (assert) {
70 | const result = Enumerable.from([1, 2, 2, 3, '3']).distinct((i1, i2) => +(i1) === +(i2)).toArray();
71 | assert.deepEqual(result, [1, 2, 3], "Passed!");
72 | });
73 |
74 | QUnit.test("Enumerable.elementAt in range array", function (assert) {
75 | const result = Enumerable.from([1, 2, 2, 3, '3']).elementAt(3);
76 | assert.deepEqual(result, 3, "Passed!");
77 | });
78 | QUnit.test("Enumerable.elementAt below range array", function (assert) {
79 | assert.throws(() => Enumerable.from([1, 2, 2, 3, '3']).elementAt(-3), "Passed!");
80 | });
81 | QUnit.test("Enumerable.elementAt above range array", function (assert) {
82 | assert.throws(() => Enumerable.from([1, 2, 2, 3, '3']).elementAt(30), "Passed!");
83 | });
84 | QUnit.test("Enumerable.elementAtOrDefault in range array", function (assert) {
85 | const result = Enumerable.from([1, 2, 2, 3, '3']).elementAtOrDefault(3);
86 | assert.deepEqual(result, 3, "Passed!");
87 | });
88 | QUnit.test("Enumerable.elementAtOrDefault below range array", function (assert) {
89 | const result = Enumerable.from([1, 2, 2, 3, '3']).elementAtOrDefault(-3);
90 | assert.deepEqual(result, undefined, "Passed!");
91 | });
92 | QUnit.test("Enumerable.elementAtOrDefault above range array", function (assert) {
93 | const result = Enumerable.from([1, 2, 2, 3, '3']).elementAtOrDefault(30);
94 | assert.deepEqual(result, undefined, "Passed!");
95 | });
96 |
97 | QUnit.test("Enumerable.first", function (assert) {
98 | const result = Enumerable.from([1, 2, 2, 3, '3']).first();
99 | assert.deepEqual(result, 1, "Passed!");
100 | });
101 | QUnit.test("Enumerable.first empty", function (assert) {
102 | assert.throws(() => Enumerable.from([]).first(), "Passed!");
103 | });
104 | QUnit.test("Enumerable.firstOrDefault", function (assert) {
105 | const result = Enumerable.from([]).firstOrDefault();
106 | assert.deepEqual(result, undefined, "Passed!");
107 | });
108 |
109 | QUnit.test("Enumerable.last", function (assert) {
110 | const result = Enumerable.from([1, 2, 2, 3, '3']).last();
111 | assert.deepEqual(result, '3', "Passed!");
112 | });
113 | QUnit.test("Enumerable.last empty", function (assert) {
114 | assert.throws(() => Enumerable.from([]).last(), "Passed!");
115 | });
116 | QUnit.test("Enumerable.lastOrDefault", function (assert) {
117 | const result = Enumerable.from([]).lastOrDefault();
118 | assert.deepEqual(result, undefined, "Passed!");
119 | });
120 |
121 | QUnit.test("Enumerable.max numbers", function (assert) {
122 | const result = Enumerable.from([3, 5, 1, 2, 56, 2, -100, 43]).max();
123 | assert.deepEqual(result, 56, "Passed!");
124 | });
125 | QUnit.test("Enumerable.max strings", function (assert) {
126 | const result = Enumerable.from(['ba', 'a', 'abba', 'aaa', 'bb']).max();
127 | assert.deepEqual(result, 'bb', "Passed!");
128 | });
129 |
130 | QUnit.test("Enumerable.min number", function (assert) {
131 | const result = Enumerable.from([3, 5, 1, 2, 56, 2, -100, 43]).min();
132 | assert.deepEqual(result, -100, "Passed!");
133 | });
134 | QUnit.test("Enumerable.min custom comparer", function (assert) {
135 | const result = Enumerable.from([3, 5, 1, 2, 56, 2, -100, 43]).min((i1, i2) => i1.toString().length - i2.toString().length);
136 | assert.deepEqual(result, 3, "Passed!");
137 | });
138 |
139 | QUnit.test("Enumerable.select", function (assert) {
140 | const result = Enumerable.from(['a', 1, 3, 2]).select(item => Number.isInteger(item) ? item * item : item + '^2').toArray();
141 | assert.deepEqual(result, ['a^2', 1, 9, 4], "Passed!");
142 | });
143 |
144 | QUnit.test("Enumerable.skip", function (assert) {
145 | const result = Enumerable.from([1, 2, 3, 4, 5]).skip(2).toArray();
146 | assert.deepEqual(result, [3, 4, 5], "Passed!");
147 | });
148 |
149 | QUnit.test("Enumerable.sum numbers", function (assert) {
150 | const result = Enumerable.from([1, 2, 3, 4, 5]).sum();
151 | assert.deepEqual(result, 15, "Passed!");
152 | });
153 | QUnit.test("Enumerable.sum numbers with some strings", function (assert) {
154 | const result = Enumerable.from([1, 2, 3, 4, 5, '6']).sum();
155 | assert.deepEqual(result, Number.NaN, "Passed!");
156 | });
157 |
158 | QUnit.test("Enumerable.take", function (assert) {
159 | const result = Enumerable.from([1, 2, 3, 4, 5]).take(2).toArray();
160 | assert.deepEqual(result, [1, 2], "Passed!");
161 | });
162 |
163 | QUnit.test("Enumerable.where", function (assert) {
164 | const result = Enumerable.from([1, 2, 3, 4, 5]).where(item => item % 2).toArray();
165 | assert.deepEqual(result, [1, 3, 5], "Passed!");
166 | });
167 | QUnit.test("Enumerable.where with index", function (assert) {
168 | const idxs = [];
169 | const result = Enumerable.from([1, 2, 3, 4, 5]).where((item, index) => {
170 | idxs.push(index);
171 | return item % 2;
172 | }).toArray();
173 | assert.deepEqual(result, [1, 3, 5], "Passed!");
174 | assert.deepEqual(idxs, [0, 1, 2, 3, 4], "Passed!");
175 | });
176 |
177 |
178 | // composable count tests
179 | QUnit.module('composable count tests');
180 |
181 | QUnit.test("Enumerable.concat seekable count ", function (assert) {
182 | const result = Enumerable.range(100, 10000).concat(Enumerable.range(10, 20000));
183 | assert.deepEqual(result.count(), 30000, "Passed!");
184 | assert.deepEqual(result._wasIterated, false, "Passed!");
185 | });
186 | QUnit.test("Enumerable.concat unseekable count", function (assert) {
187 | const iterable = Enumerable.from(function* () { yield 1; })
188 | const result = Enumerable.range(100, 10000).concat(iterable);
189 | assert.deepEqual(result.count(), 10001, "Passed!");
190 | assert.deepEqual(result._wasIterated, false, "Passed!");
191 | assert.deepEqual(iterable._wasIterated, true, "Passed!");
192 | });
193 | QUnit.test("skip count", function (assert) {
194 | const result = Enumerable.range(100, 10000).skip(5);
195 | assert.deepEqual(result.count(), 9995, "Passed!");
196 | assert.deepEqual(result._wasIterated, false, "Passed!");
197 | });
198 | QUnit.test("take count", function (assert) {
199 | const result = Enumerable.range(100, 10000).take(5);
200 | assert.deepEqual(result.count(), 5, "Passed!");
201 | assert.deepEqual(result._wasIterated, false, "Passed!");
202 | });
203 |
204 | // seek tests
205 | QUnit.module('seek tests');
206 | QUnit.test("Enumerable.empty seek", function (assert) {
207 | const result = Enumerable.from([]);
208 | assert.deepEqual(result.count(), 0, "Passed!");
209 | assert.deepEqual(result.elementAtOrDefault(10000), undefined, "Passed!");
210 | assert.deepEqual(result._wasIterated, false, "Passed!");
211 | });
212 | QUnit.test("concat array seek", function (assert) {
213 | const result = Enumerable.range(0, 100000).concat([0, 1, 2, 3, 4, 5]);
214 | assert.deepEqual(result.count(), 100006, "Passed!");
215 | assert.deepEqual(result.elementAtOrDefault(100004), 4, "Passed!");
216 | assert.deepEqual(result._wasIterated, false, "Passed!");
217 | });
218 | QUnit.test("concat Enumerable seek", function (assert) {
219 | const result = Enumerable.range(0, 100000).concat(Enumerable.range(0, 6));
220 | assert.deepEqual(result.count(), 100006, "Passed!");
221 | assert.deepEqual(result.elementAtOrDefault(100004), 4, "Passed!");
222 | assert.deepEqual(result._wasIterated, false, "Passed!");
223 | });
224 | QUnit.test("select seek", function (assert) {
225 | const result = Enumerable.range(0, 100000).select(i => 'a' + i);
226 | assert.deepEqual(result.count(), 100000, "Passed!");
227 | assert.deepEqual(result.elementAtOrDefault(10000), 'a10000', "Passed!");
228 | assert.deepEqual(result.elementAtOrDefault(1000000), undefined, "Passed!");
229 | assert.deepEqual(result._wasIterated, false, "Passed!");
230 | });
231 | QUnit.test("skip seek", function (assert) {
232 | const result = Enumerable.range(0, 100000).skip(50000);
233 | assert.deepEqual(result.count(), 50000, "Passed!");
234 | assert.deepEqual(result.elementAtOrDefault(10000), 60000, "Passed!");
235 | assert.deepEqual(result.elementAtOrDefault(1000000), undefined, "Passed!");
236 | assert.deepEqual(result._wasIterated, false, "Passed!");
237 | });
238 | QUnit.test("take seek", function (assert) {
239 | const result = Enumerable.range(0, 100000).take(50000);
240 | assert.deepEqual(result.count(), 50000, "Passed!");
241 | assert.deepEqual(result.elementAtOrDefault(10000), 10000, "Passed!");
242 | assert.deepEqual(result.elementAtOrDefault(50000), undefined, "Passed!");
243 | assert.deepEqual(result.elementAtOrDefault(1000000), undefined, "Passed!");
244 | assert.deepEqual(result._wasIterated, false, "Passed!");
245 | });
246 |
--------------------------------------------------------------------------------
/LInQer.slim.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"LInQer.Slim.js","sourceRoot":"","sources":["LInQer.Slim.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/LInQer.OrderedEnumerable.ts:
--------------------------------------------------------------------------------
1 | ///
2 | namespace Linqer {
3 |
4 | export interface Enumerable extends Iterable {
5 | /**
6 | * Sorts the elements of a sequence in ascending order.
7 | *
8 | * @param {ISelector} keySelector
9 | * @returns {OrderedEnumerable}
10 | * @memberof Enumerable
11 | */
12 | orderBy(keySelector: ISelector): OrderedEnumerable;
13 | /**
14 | * Sorts the elements of a sequence in descending order.
15 | *
16 | * @param {ISelector} keySelector
17 | * @returns {OrderedEnumerable}
18 | * @memberof Enumerable
19 | */
20 | orderByDescending(keySelector: ISelector): OrderedEnumerable;
21 | /**
22 | * use QuickSort for ordering (default). Recommended when take, skip, takeLast, skipLast are used after orderBy
23 | *
24 | * @returns {Enumerable}
25 | * @memberof Enumerable
26 | */
27 | useQuickSort(): Enumerable;
28 | /**
29 | * use the default browser sort implementation for ordering at all times
30 | *
31 | * @returns {Enumerable}
32 | * @memberof Enumerable
33 | */
34 | useBrowserSort(): Enumerable;
35 | }
36 |
37 |
38 | /// Sorts the elements of a sequence in ascending order.
39 | Enumerable.prototype.orderBy = function (keySelector: ISelector): OrderedEnumerable {
40 | if (keySelector) {
41 | _ensureFunction(keySelector);
42 | } else {
43 | keySelector = item => item;
44 | }
45 | return new OrderedEnumerable(this, keySelector, true);
46 | };
47 |
48 | /// Sorts the elements of a sequence in descending order.
49 | Enumerable.prototype.orderByDescending = function (keySelector: ISelector): OrderedEnumerable {
50 | if (keySelector) {
51 | _ensureFunction(keySelector);
52 | } else {
53 | keySelector = item => item;
54 | }
55 | return new OrderedEnumerable(this, keySelector, false);
56 | };
57 |
58 | /// use QuickSort for ordering (default). Recommended when take, skip, takeLast, skipLast are used after orderBy
59 | Enumerable.prototype.useQuickSort = function (): Enumerable {
60 | this._useQuickSort = true;
61 | return this;
62 | };
63 |
64 | /// use the default browser sort implementation for ordering at all times
65 | Enumerable.prototype.useBrowserSort = function (): Enumerable {
66 | this._useQuickSort = false;
67 | return this;
68 | };
69 |
70 |
71 | //static sort: (arr: any[], comparer?: IComparer) => void;
72 | Enumerable.sort = function (arr: any[], comparer: IComparer = _defaultComparer): any[] {
73 | _quickSort(arr, 0, arr.length - 1, comparer, 0, Number.MAX_SAFE_INTEGER);
74 | return arr;
75 | }
76 |
77 | enum RestrictionType {
78 | skip,
79 | skipLast,
80 | take,
81 | takeLast
82 | }
83 |
84 | /**
85 | * An Enumerable yielding ordered items
86 | *
87 | * @export
88 | * @class OrderedEnumerable
89 | * @extends {Enumerable}
90 | */
91 | export class OrderedEnumerable extends Enumerable {
92 | _keySelectors: { keySelector: ISelector, ascending: boolean }[];
93 | _restrictions: { type: RestrictionType, nr: number }[];
94 |
95 | /**
96 | *Creates an instance of OrderedEnumerable.
97 | * @param {IterableType} src
98 | * @param {ISelector} [keySelector]
99 | * @param {boolean} [ascending=true]
100 | * @memberof OrderedEnumerable
101 | */
102 | constructor(src: IterableType,
103 | keySelector?: ISelector,
104 | ascending: boolean = true) {
105 | super(src);
106 | this._keySelectors = [];
107 | this._restrictions = [];
108 | if (keySelector) {
109 | this._keySelectors.push({ keySelector: keySelector, ascending: ascending });
110 | }
111 | const self: OrderedEnumerable = this;
112 | // generator gets an array of the original,
113 | // sorted inside the interval determined by functions such as skip, take, skipLast, takeLast
114 | this._generator = function* () {
115 | let { startIndex, endIndex, arr } = this.getSortedArray();
116 | if (arr) {
117 | for (let index = startIndex; index < endIndex; index++) {
118 | yield arr[index];
119 | }
120 | }
121 | };
122 |
123 | // the count is the difference between the end and start indexes
124 | // if no skip/take functions were used, this will be the original count
125 | this._count = () => {
126 | const totalCount = Enumerable.from(self._src).count();
127 | const { startIndex, endIndex } = this.getStartAndEndIndexes(self._restrictions, totalCount);
128 | return endIndex - startIndex;
129 | };
130 | // an ordered enumerable cannot seek
131 | this._canSeek=false;
132 | this._tryGetAt = ()=>{ throw new Error('Ordered enumerables cannot seek'); };
133 | }
134 |
135 | private getSortedArray() {
136 | const self = this;
137 | let startIndex: number;
138 | let endIndex: number;
139 | let arr: any[] | null = null;
140 | const innerEnumerable = self._src as Enumerable;
141 | _ensureInternalTryGetAt(innerEnumerable);
142 | // try to avoid enumerating the entire original into an array
143 | if (innerEnumerable._canSeek) {
144 | ({ startIndex, endIndex } = self.getStartAndEndIndexes(self._restrictions, innerEnumerable.count()));
145 | } else {
146 | arr = Array.from(self._src);
147 | ({ startIndex, endIndex } = self.getStartAndEndIndexes(self._restrictions, arr.length));
148 | }
149 | if (startIndex < endIndex) {
150 | if (!arr) {
151 | arr = Array.from(self._src);
152 | }
153 | // only quicksort supports partial ordering inside an interval
154 | const sort: (item1: any, item2: any) => void = self._useQuickSort
155 | ? (a, c) => _quickSort(a, 0, a.length - 1, c, startIndex, endIndex)
156 | : (a, c) => a.sort(c);
157 | const sortFunc = self.generateSortFunc(self._keySelectors);
158 | sort(arr, sortFunc);
159 | return {
160 | startIndex,
161 | endIndex,
162 | arr
163 | };
164 | } else {
165 | return {
166 | startIndex,
167 | endIndex,
168 | arr: null
169 | };
170 | }
171 | }
172 |
173 | private generateSortFunc(selectors: { keySelector: ISelector, ascending: boolean }[]): (i1: any, i2: any) => number {
174 | // simplify the selectors into an array of comparers
175 | const comparers = selectors.map(s => {
176 | const f = s.keySelector;
177 | const comparer = (i1: any, i2: any) => {
178 | const k1 = f(i1);
179 | const k2 = f(i2);
180 | if (k1 > k2) return 1;
181 | if (k1 < k2) return -1;
182 | return 0;
183 | };
184 | return s.ascending
185 | ? comparer
186 | : (i1: any, i2: any) => -comparer(i1, i2);
187 | });
188 | // optimize the resulting sort function in the most common case
189 | // (ordered by a single criterion)
190 | return comparers.length == 1
191 | ? comparers[0]
192 | : (i1: any, i2: any) => {
193 | for (let i = 0; i < comparers.length; i++) {
194 | const v = comparers[i](i1, i2);
195 | if (v) return v;
196 | }
197 | return 0;
198 | };
199 | }
200 |
201 | /// calculate the interval in which an array needs to have ordered items for this ordered enumerable
202 | private getStartAndEndIndexes(restrictions: { type: RestrictionType, nr: number }[], arrLength: number) {
203 | let startIndex = 0;
204 | let endIndex = arrLength;
205 | for (const restriction of restrictions) {
206 | switch (restriction.type) {
207 | case RestrictionType.take:
208 | endIndex = Math.min(endIndex, startIndex + restriction.nr);
209 | break;
210 | case RestrictionType.skip:
211 | startIndex = Math.min(endIndex, startIndex + restriction.nr);
212 | break;
213 | case RestrictionType.takeLast:
214 | startIndex = Math.max(startIndex, endIndex - restriction.nr);
215 | break;
216 | case RestrictionType.skipLast:
217 | endIndex = Math.max(startIndex, endIndex - restriction.nr);
218 | break;
219 | }
220 | }
221 | return { startIndex, endIndex };
222 | }
223 |
224 |
225 | /**
226 | * Performs a subsequent ordering of the elements in a sequence in ascending order.
227 | *
228 | * @param {ISelector} keySelector
229 | * @returns {OrderedEnumerable}
230 | * @memberof OrderedEnumerable
231 | */
232 | thenBy(keySelector: ISelector): OrderedEnumerable {
233 | this._keySelectors.push({ keySelector: keySelector, ascending: true });
234 | return this;
235 | }
236 | /**
237 | * Performs a subsequent ordering of the elements in a sequence in descending order.
238 | *
239 | * @param {ISelector} keySelector
240 | * @returns {OrderedEnumerable}
241 | * @memberof OrderedEnumerable
242 | */
243 | thenByDescending(keySelector: ISelector): OrderedEnumerable {
244 | this._keySelectors.push({ keySelector: keySelector, ascending: false });
245 | return this;
246 | }
247 |
248 | /**
249 | * Deferred and optimized implementation of take
250 | *
251 | * @param {number} nr
252 | * @returns {OrderedEnumerable}
253 | * @memberof OrderedEnumerable
254 | */
255 | take(nr: number): OrderedEnumerable {
256 | this._restrictions.push({ type: RestrictionType.take, nr: nr });
257 | return this;
258 | }
259 |
260 | /**
261 | * Deferred and optimized implementation of takeLast
262 | *
263 | * @param {number} nr
264 | * @returns {OrderedEnumerable}
265 | * @memberof OrderedEnumerable
266 | */
267 | takeLast(nr: number): OrderedEnumerable {
268 | this._restrictions.push({ type: RestrictionType.takeLast, nr: nr });
269 | return this;
270 | }
271 |
272 | /**
273 | * Deferred and optimized implementation of skip
274 | *
275 | * @param {number} nr
276 | * @returns {OrderedEnumerable}
277 | * @memberof OrderedEnumerable
278 | */
279 | skip(nr: number): OrderedEnumerable {
280 | this._restrictions.push({ type: RestrictionType.skip, nr: nr });
281 | return this;
282 | }
283 |
284 | /**
285 | * Deferred and optimized implementation of skipLast
286 | *
287 | * @param {number} nr
288 | * @returns {OrderedEnumerable}
289 | * @memberof OrderedEnumerable
290 | */
291 | skipLast(nr: number): OrderedEnumerable {
292 | this._restrictions.push({ type: RestrictionType.skipLast, nr: nr });
293 | return this;
294 | }
295 |
296 |
297 | /**
298 | * An optimized implementation of toArray
299 | *
300 | * @returns {any[]}
301 | * @memberof OrderedEnumerable
302 | */
303 | toArray(): any[] {
304 | const { startIndex, endIndex, arr } = this.getSortedArray();
305 | return arr
306 | ? arr.slice(startIndex, endIndex)
307 | : [];
308 | }
309 |
310 |
311 | /**
312 | * An optimized implementation of toMap
313 | *
314 | * @param {ISelector} keySelector
315 | * @param {ISelector} [valueSelector=x => x]
316 | * @returns {Map}
317 | * @memberof OrderedEnumerable
318 | */
319 | toMap(keySelector: ISelector, valueSelector: ISelector = x => x): Map {
320 | _ensureFunction(keySelector);
321 | _ensureFunction(valueSelector);
322 | const result = new Map();
323 | const arr = this.toArray();
324 | for (let i = 0; i < arr.length; i++) {
325 | result.set(keySelector(arr[i], i), valueSelector(arr[i], i));
326 | }
327 | return result;
328 | }
329 |
330 |
331 | /**
332 | * An optimized implementation of toObject
333 | *
334 | * @param {ISelector} keySelector
335 | * @param {ISelector} [valueSelector=x => x]
336 | * @returns {{ [key: string]: any }}
337 | * @memberof OrderedEnumerable
338 | */
339 | toObject(keySelector: ISelector, valueSelector: ISelector = x => x): { [key: string]: any } {
340 | _ensureFunction(keySelector);
341 | _ensureFunction(valueSelector);
342 | const result: { [key: string]: any } = {};
343 | const arr = this.toArray();
344 | for (let i = 0; i < arr.length; i++) {
345 | result[keySelector(arr[i], i)] = valueSelector(arr[i], i);
346 | }
347 | return result;
348 | }
349 |
350 |
351 | /**
352 | * An optimized implementation of to Set
353 | *
354 | * @returns {Set}
355 | * @memberof OrderedEnumerable
356 | */
357 | toSet(): Set {
358 | const result = new Set();
359 | const arr = this.toArray();
360 | for (let i = 0; i < arr.length; i++) {
361 | result.add(arr[i]);
362 | }
363 | return result;
364 | }
365 |
366 | }
367 |
368 |
369 | const _insertionSortThreshold = 64;
370 | /// insertion sort is used for small intervals
371 | function _insertionsort(arr: any[], leftIndex: number, rightIndex: number, comparer: IComparer) {
372 | for (let j = leftIndex; j <= rightIndex; j++) {
373 | const key = arr[j];
374 | let i = j - 1;
375 | while (i >= leftIndex && comparer(arr[i], key) > 0) {
376 | arr[i + 1] = arr[i];
377 | i--;
378 | }
379 | arr[i + 1] = key;
380 | }
381 | }
382 |
383 | /// swap two items in an array by index
384 | function _swapArrayItems(array: any[], leftIndex: number, rightIndex: number): void {
385 | const temp = array[leftIndex];
386 | array[leftIndex] = array[rightIndex];
387 | array[rightIndex] = temp;
388 | }
389 | // Quicksort partition by center value coming from both sides
390 | function _partition(items: any[], left: number, right: number, comparer: IComparer) {
391 | const pivot = items[(right + left) >> 1];
392 | while (left <= right) {
393 | while (comparer(items[left], pivot) < 0) {
394 | left++;
395 | }
396 | while (comparer(items[right], pivot) > 0) {
397 | right--;
398 | }
399 | if (left < right) {
400 | _swapArrayItems(items, left, right);
401 | left++;
402 | right--;
403 | } else {
404 | if (left === right) return left + 1;
405 | }
406 | }
407 | return left;
408 | }
409 |
410 | /// optimized Quicksort algorithm
411 | function _quickSort(items: any[], left: number, right: number, comparer: IComparer = _defaultComparer, minIndex: number = 0, maxIndex: number = Number.MAX_SAFE_INTEGER) {
412 | if (!items.length) return items;
413 |
414 | // store partition indexes to be processed in here
415 | const partitions: { left: number, right: number }[] = [];
416 | partitions.push({ left, right });
417 | let size = 1;
418 | // the actual size of the partitions array never decreases
419 | // but we keep score of the number of partitions in 'size'
420 | // and we reuse slots whenever possible
421 | while (size) {
422 | const partition = { left, right } = partitions[size-1];
423 | if (right - left < _insertionSortThreshold) {
424 | _insertionsort(items, left, right, comparer);
425 | size--;
426 | continue;
427 | }
428 | const index = _partition(items, left, right, comparer);
429 | if (left < index - 1 && index - 1 >= minIndex) {
430 | partition.right = index - 1;
431 | if (index < right && index < maxIndex) {
432 | partitions[size]={ left: index, right };
433 | size++;
434 | }
435 | } else {
436 | if (index < right && index < maxIndex) {
437 | partition.left = index;
438 | } else {
439 | size--;
440 | }
441 | }
442 | }
443 | return items;
444 | }
445 | }
--------------------------------------------------------------------------------
/LInQer.extra.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | ///
3 | ///
4 | ///
5 | var Linqer;
6 | ///
7 | ///
8 | ///
9 | (function (Linqer) {
10 | /// randomizes the enumerable (partial Fisher-Yates)
11 | Linqer.Enumerable.prototype.shuffle = function () {
12 | const self = this;
13 | function* gen() {
14 | const arr = self.toArray();
15 | const len = arr.length;
16 | let n = 0;
17 | while (n < len) {
18 | let k = n + Math.floor(Math.random() * (len - n));
19 | const value = arr[k];
20 | arr[k] = arr[n];
21 | arr[n] = value;
22 | n++;
23 | yield value;
24 | }
25 | }
26 | const result = Linqer.Enumerable.from(gen);
27 | result._count = () => self.count();
28 | return result;
29 | };
30 | /// implements random reservoir sampling of k items, with the option to specify a maximum limit for the items
31 | Linqer.Enumerable.prototype.randomSample = function (k, limit = Number.MAX_SAFE_INTEGER) {
32 | let index = 0;
33 | const sample = [];
34 | Linqer._ensureInternalTryGetAt(this);
35 | if (this._canSeek) { // L algorithm
36 | const length = this.count();
37 | let index = 0;
38 | for (index = 0; index < k && index < limit && index < length; index++) {
39 | sample.push(this.elementAt(index));
40 | }
41 | let W = Math.exp(Math.log(Math.random()) / k);
42 | while (index < length && index < limit) {
43 | index += Math.floor(Math.log(Math.random()) / Math.log(1 - W)) + 1;
44 | if (index < length && index < limit) {
45 | sample[Math.floor(Math.random() * k)] = this.elementAt(index);
46 | W *= Math.exp(Math.log(Math.random()) / k);
47 | }
48 | }
49 | }
50 | else { // R algorithm
51 | for (const item of this) {
52 | if (index < k) {
53 | sample.push(item);
54 | }
55 | else {
56 | const j = Math.floor(Math.random() * index);
57 | if (j < k) {
58 | sample[j] = item;
59 | }
60 | }
61 | index++;
62 | if (index >= limit)
63 | break;
64 | }
65 | }
66 | return Linqer.Enumerable.from(sample);
67 | };
68 | /// returns the distinct values based on a hashing function
69 | Linqer.Enumerable.prototype.distinctByHash = function (hashFunc) {
70 | // this is much more performant than distinct with a custom comparer
71 | const self = this;
72 | const gen = function* () {
73 | const distinctValues = new Set();
74 | for (const item of self) {
75 | const size = distinctValues.size;
76 | distinctValues.add(hashFunc(item));
77 | if (size < distinctValues.size) {
78 | yield item;
79 | }
80 | }
81 | };
82 | return new Linqer.Enumerable(gen);
83 | };
84 | /// returns the values that have different hashes from the items of the iterable provided
85 | Linqer.Enumerable.prototype.exceptByHash = function (iterable, hashFunc) {
86 | // this is much more performant than except with a custom comparer
87 | Linqer._ensureIterable(iterable);
88 | const self = this;
89 | const gen = function* () {
90 | const distinctValues = Linqer.Enumerable.from(iterable).select(hashFunc).toSet();
91 | for (const item of self) {
92 | if (!distinctValues.has(hashFunc(item))) {
93 | yield item;
94 | }
95 | }
96 | };
97 | return new Linqer.Enumerable(gen);
98 | };
99 | /// returns the values that have the same hashes as items of the iterable provided
100 | Linqer.Enumerable.prototype.intersectByHash = function (iterable, hashFunc) {
101 | // this is much more performant than intersect with a custom comparer
102 | Linqer._ensureIterable(iterable);
103 | const self = this;
104 | const gen = function* () {
105 | const distinctValues = Linqer.Enumerable.from(iterable).select(hashFunc).toSet();
106 | for (const item of self) {
107 | if (distinctValues.has(hashFunc(item))) {
108 | yield item;
109 | }
110 | }
111 | };
112 | return new Linqer.Enumerable(gen);
113 | };
114 | /// returns the index of a value in an ordered enumerable or false if not found
115 | /// WARNING: use the same comparer as the one used in the ordered enumerable. The algorithm assumes the enumerable is already sorted.
116 | Linqer.Enumerable.prototype.binarySearch = function (value, comparer = Linqer._defaultComparer) {
117 | let enumerable = this.toList();
118 | let start = 0;
119 | let end = enumerable.count() - 1;
120 | while (start <= end) {
121 | const mid = (start + end) >> 1;
122 | const comp = comparer(enumerable.elementAt(mid), value);
123 | if (comp == 0)
124 | return mid;
125 | if (comp < 0) {
126 | start = mid + 1;
127 | }
128 | else {
129 | end = mid - 1;
130 | }
131 | }
132 | return false;
133 | };
134 | /// joins each item of the enumerable with previous items from the same enumerable
135 | Linqer.Enumerable.prototype.lag = function (offset, zipper) {
136 | if (!offset) {
137 | throw new Error('offset has to be positive');
138 | }
139 | if (offset < 0) {
140 | throw new Error('offset has to be positive. Use .lead if you want to join with next items');
141 | }
142 | if (!zipper) {
143 | zipper = (i1, i2) => [i1, i2];
144 | }
145 | else {
146 | Linqer._ensureFunction(zipper);
147 | }
148 | const self = this;
149 | Linqer._ensureInternalTryGetAt(this);
150 | // generator uses a buffer to hold all the items within the offset interval
151 | const gen = function* () {
152 | const buffer = Array(offset);
153 | let index = 0;
154 | for (const item of self) {
155 | const index2 = index - offset;
156 | const item2 = index2 < 0
157 | ? undefined
158 | : buffer[index2 % offset];
159 | yield zipper(item, item2);
160 | buffer[index % offset] = item;
161 | index++;
162 | }
163 | };
164 | const result = new Linqer.Enumerable(gen);
165 | // count is the same as of the original enumerable
166 | result._count = () => {
167 | const count = self.count();
168 | if (!result._wasIterated)
169 | result._wasIterated = self._wasIterated;
170 | return count;
171 | };
172 | // seeking is possible only if the original was seekable
173 | if (self._canSeek) {
174 | result._canSeek = true;
175 | result._tryGetAt = (index) => {
176 | const val1 = self._tryGetAt(index);
177 | const val2 = self._tryGetAt(index - offset);
178 | if (val1) {
179 | return {
180 | value: zipper(val1.value, val2 ? val2.value : undefined)
181 | };
182 | }
183 | return null;
184 | };
185 | }
186 | return result;
187 | };
188 | /// joins each item of the enumerable with next items from the same enumerable
189 | Linqer.Enumerable.prototype.lead = function (offset, zipper) {
190 | if (!offset) {
191 | throw new Error('offset has to be positive');
192 | }
193 | if (offset < 0) {
194 | throw new Error('offset has to be positive. Use .lag if you want to join with previous items');
195 | }
196 | if (!zipper) {
197 | zipper = (i1, i2) => [i1, i2];
198 | }
199 | else {
200 | Linqer._ensureFunction(zipper);
201 | }
202 | const self = this;
203 | Linqer._ensureInternalTryGetAt(this);
204 | // generator uses a buffer to hold all the items within the offset interval
205 | const gen = function* () {
206 | const buffer = Array(offset);
207 | let index = 0;
208 | for (const item of self) {
209 | const index2 = index - offset;
210 | if (index2 >= 0) {
211 | const item2 = buffer[index2 % offset];
212 | yield zipper(item2, item);
213 | }
214 | buffer[index % offset] = item;
215 | index++;
216 | }
217 | for (let i = 0; i < offset; i++) {
218 | const item = buffer[(index + i) % offset];
219 | yield zipper(item, undefined);
220 | }
221 | };
222 | const result = new Linqer.Enumerable(gen);
223 | // count is the same as of the original enumerable
224 | result._count = () => {
225 | const count = self.count();
226 | if (!result._wasIterated)
227 | result._wasIterated = self._wasIterated;
228 | return count;
229 | };
230 | // seeking is possible only if the original was seekable
231 | if (self._canSeek) {
232 | result._canSeek = true;
233 | result._tryGetAt = (index) => {
234 | const val1 = self._tryGetAt(index);
235 | const val2 = self._tryGetAt(index + offset);
236 | if (val1) {
237 | return {
238 | value: zipper(val1.value, val2 ? val2.value : undefined)
239 | };
240 | }
241 | return null;
242 | };
243 | }
244 | return result;
245 | };
246 | /// returns an enumerable of at least minLength, padding the end with a value or the result of a function
247 | Linqer.Enumerable.prototype.padEnd = function (minLength, filler) {
248 | if (minLength <= 0) {
249 | throw new Error('minLength has to be positive.');
250 | }
251 | let fillerFunc;
252 | if (typeof filler !== 'function') {
253 | fillerFunc = (index) => filler;
254 | }
255 | else {
256 | fillerFunc = filler;
257 | }
258 | const self = this;
259 | Linqer._ensureInternalTryGetAt(this);
260 | // generator iterates all elements,
261 | // then yields the result of the filler function until minLength items
262 | const gen = function* () {
263 | let index = 0;
264 | for (const item of self) {
265 | yield item;
266 | index++;
267 | }
268 | for (; index < minLength; index++) {
269 | yield fillerFunc(index);
270 | }
271 | };
272 | const result = new Linqer.Enumerable(gen);
273 | // count is the maximum between minLength and the original count
274 | result._count = () => {
275 | const count = Math.max(minLength, self.count());
276 | if (!result._wasIterated)
277 | result._wasIterated = self._wasIterated;
278 | return count;
279 | };
280 | // seeking is possible if the original was seekable
281 | if (self._canSeek) {
282 | result._canSeek = true;
283 | result._tryGetAt = (index) => {
284 | const val = self._tryGetAt(index);
285 | if (val)
286 | return val;
287 | if (index < minLength) {
288 | return { value: fillerFunc(index) };
289 | }
290 | return null;
291 | };
292 | }
293 | return result;
294 | };
295 | /// returns an enumerable of at least minLength, padding the start with a value or the result of a function
296 | /// if the enumerable cannot seek, then it will be iterated minLength time
297 | Linqer.Enumerable.prototype.padStart = function (minLength, filler) {
298 | if (minLength <= 0) {
299 | throw new Error('minLength has to be positive.');
300 | }
301 | let fillerFunc;
302 | if (typeof filler !== 'function') {
303 | fillerFunc = (index) => filler;
304 | }
305 | else {
306 | fillerFunc = filler;
307 | }
308 | const self = this;
309 | Linqer._ensureInternalTryGetAt(self);
310 | // generator needs a buffer to hold offset values
311 | // it yields values from the buffer when it overflows
312 | // or filler function results if the buffer is not full
313 | // after iterating the entire original enumerable
314 | const gen = function* () {
315 | const buffer = Array(minLength);
316 | let index = 0;
317 | const iterator = self[Symbol.iterator]();
318 | let flushed = false;
319 | let done = false;
320 | do {
321 | const val = iterator.next();
322 | done = !!val.done;
323 | if (!done) {
324 | buffer[index] = val.value;
325 | index++;
326 | }
327 | if (flushed && !done) {
328 | yield val.value;
329 | }
330 | else {
331 | if (done || index === minLength) {
332 | for (let i = 0; i < minLength - index; i++) {
333 | yield fillerFunc(i);
334 | }
335 | for (let i = 0; i < index; i++) {
336 | yield buffer[i];
337 | }
338 | flushed = true;
339 | }
340 | }
341 | } while (!done);
342 | };
343 | const result = new Linqer.Enumerable(gen);
344 | // count is the max of minLength and the original count
345 | result._count = () => {
346 | const count = Math.max(minLength, self.count());
347 | if (!result._wasIterated)
348 | result._wasIterated = self._wasIterated;
349 | return count;
350 | };
351 | // seeking is possible only if the original was seekable
352 | if (self._canSeek) {
353 | result._canSeek = true;
354 | result._tryGetAt = (index) => {
355 | const count = self.count();
356 | const delta = minLength - count;
357 | if (delta <= 0) {
358 | return self._tryGetAt(index);
359 | }
360 | if (index < delta) {
361 | return { value: fillerFunc(index) };
362 | }
363 | return self._tryGetAt(index - delta);
364 | };
365 | }
366 | return result;
367 | };
368 | })(Linqer || (Linqer = {}));
369 | //# sourceMappingURL=LInQer.extra.js.map
--------------------------------------------------------------------------------
/LInQer.min.js:
--------------------------------------------------------------------------------
1 | "use strict";var Linqer;!function(t){class e{constructor(t){n(t),this._src=t;const e=t[Symbol.iterator];this._generator=e?e.bind(t):t,this._useQuickSort=void 0===t._useQuickSort||t._useQuickSort,this._canSeek=!1,this._count=null,this._tryGetAt=null,this._wasIterated=!1}static from(t){return t instanceof e?t:new e(t)}[Symbol.iterator](){return this._wasIterated=!0,this._generator()}static empty(){const t=new e([]);return t._count=()=>0,t._tryGetAt=t=>null,t._canSeek=!0,t}static range(t,n){const r=new e((function*(){for(let e=0;en,r._tryGetAt=e=>e>=0&&en,r._tryGetAt=e=>e>=0&&er.count()+u.count(),s(this),s(u),o._canSeek=r._canSeek&&u._canSeek,r._canSeek&&(o._tryGetAt=t=>r._tryGetAt(t)||u._tryGetAt(t-r.count())),o}count(){return u(this),this._count()}distinct(n=t.EqualityComparer.default){const r=this,o=n===t.EqualityComparer.default?function*(){const t=new Set;for(const e of r){const n=t.size;t.add(e),n0)&&(n.max=t),n.count++;return n}min(t){const e=this.stats(t);return 0===e.count?void 0:e.min}max(t){const e=this.stats(t);return 0===e.count?void 0:e.max}select(t){r(t);const n=this,o=new e((function*(){let e=0;for(const r of n)yield t(r,e),e++}));return u(this),o._count=this._count,s(n),o._canSeek=n._canSeek,o._tryGetAt=e=>{const r=n._tryGetAt(e);return r?{value:t(r.value)}:r},o}skip(t){const n=this,r=new e((function*(){let e=t;for(const t of n)e>0?e--:yield t}));return r._count=()=>Math.max(0,n.count()-t),s(this),r._canSeek=this._canSeek,r._tryGetAt=e=>n._tryGetAt(e+t),r}splice(t,e,...n){return this.take(t).concat(n).concat(this.skip(t+e))}sum(){const t=this.sumAndCount();return 0===t.count?void 0:t.sum}sumAndCount(){const t={count:0,sum:0};for(const e of this)t.sum=0===t.count?o(e):t.sum+o(e),t.count++;return t}take(t){const n=this,r=new e((function*(){let e=t;for(const t of n)if(e>0&&(yield t,e--),e<=0)break}));return r._count=()=>Math.min(t,n.count()),s(this),r._canSeek=n._canSeek,n._canSeek&&(r._tryGetAt=e=>e>=t?null:n._tryGetAt(e)),r}toArray(){var t;if(s(this),this._canSeek){const e=new Array(this.count());for(let n=0;ne._count())}const n=t._src;"function"==typeof n||"number"!=typeof n.length?"number"!=typeof n.size?t._count=()=>{let e=0;for(const n of t)e++;return e}:t._count=()=>n.size:t._count=()=>n.length}function s(t){if(t._tryGetAt)return;if(t._canSeek=!0,t._src instanceof e){const e=t._src;return s(e),t._tryGetAt=t=>e._tryGetAt(t),void(t._canSeek=e._canSeek)}if("string"==typeof t._src)return void(t._tryGetAt=e=>ee>=0&&e{let n=0;for(const r of t){if(e===n)return{value:r};n++}return null}):t._tryGetAt=t=>tt>e?1:tt==e,exact:(t,e)=>t===e}}(Linqer||(Linqer={})),function(t){t.Enumerable.prototype.aggregate=function(e,n){t._ensureFunction(n);for(const t of this)e=n(e,t);return e},t.Enumerable.prototype.all=function(e){return t._ensureFunction(e),!this.any(t=>!e(t))},t.Enumerable.prototype.any=function(e){t._ensureFunction(e);let n=0;for(const t of this){if(e(t,n))return!0;n++}return!1},t.Enumerable.prototype.append=function(t){return this.concat([t])},t.Enumerable.prototype.average=function(){const t=this.sumAndCount();return 0===t.count?void 0:t.sum/t.count},t.Enumerable.prototype.asEnumerable=function(){return this},t.Enumerable.prototype.cast=function(t){const e="string"==typeof t?e=>typeof e===t:e=>e instanceof t;return this.select(n=>{if(!e(n))throw new Error(n+" not of type "+t);return n})},t.Enumerable.prototype.contains=function(e,n=t.EqualityComparer.default){return t._ensureFunction(n),this.any(t=>n(t,e))},t.Enumerable.prototype.defaultIfEmpty=function(){throw new Error("defaultIfEmpty not implemented for Javascript")},t.Enumerable.prototype.except=function(e,n=t.EqualityComparer.default){t._ensureIterable(e);const r=this,o=n===t.EqualityComparer.default?function*(){const n=t.Enumerable.from(e).toSet();for(const t of r)n.has(t)||(yield t)}:function*(){const o=t._toArray(e);for(const t of r){let e=!0;for(let r=0;rtypeof e===t:e=>e instanceof t;return this.where(e)},t.Enumerable.prototype.prepend=function(e){return new t.Enumerable([e]).concat(this)},t.Enumerable.prototype.reverse=function(){t._ensureInternalTryGetAt(this);const e=this,n=this._canSeek?function*(){for(let t=e.count()-1;t>=0;t--)yield e.elementAt(t)}:function*(){const t=e.toArray();for(let e=t.length-1;e>=0;e--)yield t[e]},r=new t.Enumerable(n);if(t._ensureInternalCount(this),r._count=this._count,t._ensureInternalTryGetAt(this),this._canSeek){const t=this;r._canSeek=!0,r._tryGetAt=e=>t._tryGetAt(t.count()-e-1)}return r},t.Enumerable.prototype.selectMany=function(e){void 0!==e?t._ensureFunction(e):e=t=>t;const n=this;return new t.Enumerable((function*(){let r=0;for(const o of n){const n=e(o,r);t._ensureIterable(n);for(const t of n)yield t;r++}}))},t.Enumerable.prototype.sequenceEqual=function(e,n=t.EqualityComparer.default){t._ensureIterable(e),t._ensureFunction(n);const r=this[Symbol.iterator](),o=t.Enumerable.from(e)[Symbol.iterator]();let u=!1;do{const t=r.next(),e=o.next();if(!(t.done&&e.done||!t.done&&!e.done&&n(t.value,e.value)))return!1;u=!!t.done}while(!u);return!0},t.Enumerable.prototype.single=function(){const t=this[Symbol.iterator]();let e=t.next();if(e.done)throw new Error("Sequence contains no elements");const n=e.value;if(e=t.next(),!e.done)throw new Error("Sequence contains more than one element");return n},t.Enumerable.prototype.singleOrDefault=function(){const t=this[Symbol.iterator]();let e=t.next();if(e.done)return;const n=e.value;if(e=t.next(),!e.done)throw new Error("Sequence contains more than one element");return n},t.Enumerable.prototype.slice=function(t=0,e){let n=this;return void 0!==e&&e>=0&&(t||0)<0&&(n=n.toList(),t=n.count()+t),0!==t&&(n=t>0?n.skip(t):n.takeLast(-t)),void 0!==e&&(n=e>=0?n.take(e-t):n.skipLast(-e)),n},t.Enumerable.prototype.skipLast=function(e){const n=this,r=new t.Enumerable((function*(){let t=e;const r=Array(t);let o=0,u=0;for(const e of n){const n=r[o-u];r[o-u]=e,o++,o-u>=t&&(u+=t),o>t&&(yield n)}r.length=0}));return r._count=()=>Math.max(0,n.count()-e),t._ensureInternalTryGetAt(this),r._canSeek=this._canSeek,this._canSeek&&(r._tryGetAt=t=>t>=r.count()?null:n._tryGetAt(t)),r},t.Enumerable.prototype.skipWhile=function(e){t._ensureFunction(e);const n=this;let r=!0;return new t.Enumerable((function*(){let t=0;for(const o of n)r&&!e(o,t)&&(r=!1),r||(yield o),t++}))},t.Enumerable.prototype.takeLast=function(e){t._ensureInternalTryGetAt(this);const n=this,r=this._canSeek?function*(){let t=e;const r=n.count();for(let e=r-t;eMath.min(e,n.count()),o._canSeek=n._canSeek,n._canSeek&&(o._tryGetAt=t=>t<0||t>=o.count()?null:n._tryGetAt(n.count()-e+t)),o},t.Enumerable.prototype.takeWhile=function(e){t._ensureFunction(e);const n=this;return new t.Enumerable((function*(){let t=0;for(const r of n){if(!e(r,t))break;yield r,t++}}))},t.Enumerable.prototype.toDictionary=function(){throw new Error("use toMap or toObject instead of toDictionary")},t.Enumerable.prototype.toMap=function(e,n=(t=>t)){t._ensureFunction(e),t._ensureFunction(n);const r=new Map;let o=0;for(const t of this)r.set(e(t,o),n(t,o)),o++;return r},t.Enumerable.prototype.toObject=function(e,n=(t=>t)){t._ensureFunction(e),t._ensureFunction(n);const r={};let o=0;for(const t of this)r[e(t,o)]=n(t),o++;return r},t.Enumerable.prototype.toHashSet=function(){throw new Error("use toSet instead of toHashSet")},t.Enumerable.prototype.toSet=function(){const t=new Set;for(const e of this)t.add(e);return t},t.Enumerable.prototype.union=function(e,n=t.EqualityComparer.default){return t._ensureIterable(e),this.concat(e).distinct(n)},t.Enumerable.prototype.zip=function(e,n){t._ensureIterable(e),n?t._ensureFunction(n):n=(t,e)=>[t,e];const r=this;return new t.Enumerable((function*(){let o=0;const u=r[Symbol.iterator](),s=t.Enumerable.from(e)[Symbol.iterator]();let i=!1;do{const t=u.next(),e=s.next();i=!(!t.done&&!e.done),i||(yield n(t.value,e.value,o)),o++}while(!i)}))}}(Linqer||(Linqer={})),function(t){t.Enumerable.prototype.groupBy=function(n){t._ensureFunction(n);const r=this;return new t.Enumerable((function*(){const t=new Map;let o=0;for(const e of r){const r=n(e,o),u=t.get(r);u?u.push(e):t.set(r,[e]),o++}for(const[n,r]of t){const t=new e(r,n);yield t}}))},t.Enumerable.prototype.groupJoin=function(e,n,r,o,u=t.EqualityComparer.default){const s=this,i=u===t.EqualityComparer.default?function*(){const u=new t.Enumerable(e).groupBy(r).toMap(t=>t.key,t=>t);let i=0;for(const e of s){const r=t._toArray(u.get(n(e,i)));yield o(e,r),i++}}:function*(){let i=0;for(const c of s){const s=[];let a=0;for(const o of t.Enumerable.from(e))u(n(c,i),r(o,a))&&s.push(o),a++;yield o(c,s),i++}};return new t.Enumerable(i)},t.Enumerable.prototype.join=function(e,n,r,o,u=t.EqualityComparer.default){const s=this,i=u===t.EqualityComparer.default?function*(){const u=new t.Enumerable(e).groupBy(r).toMap(t=>t.key,t=>t);let i=0;for(const t of s){const e=u.get(n(t,i));if(e)for(const n of e)yield o(t,n);i++}}:function*(){let i=0;for(const c of s){let s=0;for(const a of t.Enumerable.from(e))u(n(c,i),r(a,s))&&(yield o(c,a)),s++;i++}};return new t.Enumerable(i)},t.Enumerable.prototype.toLookup=function(){throw new Error("use groupBy instead of toLookup")};class e extends t.Enumerable{constructor(t,e){super(t),this.key=e}}t.GroupEnumerable=e}(Linqer||(Linqer={})),function(t){let e;t.Enumerable.prototype.orderBy=function(e){return e?t._ensureFunction(e):e=t=>t,new n(this,e,!0)},t.Enumerable.prototype.orderByDescending=function(e){return e?t._ensureFunction(e):e=t=>t,new n(this,e,!1)},t.Enumerable.prototype.useQuickSort=function(){return this._useQuickSort=!0,this},t.Enumerable.prototype.useBrowserSort=function(){return this._useQuickSort=!1,this},t.Enumerable.sort=function(e,n=t._defaultComparer){return s(e,0,e.length-1,n,0,Number.MAX_SAFE_INTEGER),e},function(t){t[t.skip=0]="skip",t[t.skipLast=1]="skipLast",t[t.take=2]="take",t[t.takeLast=3]="takeLast"}(e||(e={}));class n extends t.Enumerable{constructor(e,n,r=!0){super(e),this._keySelectors=[],this._restrictions=[],n&&this._keySelectors.push({keySelector:n,ascending:r});const o=this;this._generator=function*(){let{startIndex:t,endIndex:e,arr:n}=this.getSortedArray();if(n)for(let r=t;r{const e=t.Enumerable.from(o._src).count(),{startIndex:n,endIndex:r}=this.getStartAndEndIndexes(o._restrictions,e);return r-n},this._canSeek=!1,this._tryGetAt=()=>{throw new Error("Ordered enumerables cannot seek")}}getSortedArray(){const e=this;let n,r,o=null;const u=e._src;if(t._ensureInternalTryGetAt(u),u._canSeek?({startIndex:n,endIndex:r}=e.getStartAndEndIndexes(e._restrictions,u.count())):(o=Array.from(e._src),({startIndex:n,endIndex:r}=e.getStartAndEndIndexes(e._restrictions,o.length))),ns(t,0,t.length-1,e,n,r):(t,e)=>t.sort(e))(o,e.generateSortFunc(e._keySelectors)),{startIndex:n,endIndex:r,arr:o}}return{startIndex:n,endIndex:r,arr:null}}generateSortFunc(t){const e=t.map(t=>{const e=t.keySelector,n=(t,n)=>{const r=e(t),o=e(n);return r>o?1:r-n(t,e)});return 1==e.length?e[0]:(t,n)=>{for(let r=0;rt)){t._ensureFunction(e),t._ensureFunction(n);const r=new Map,o=this.toArray();for(let t=0;tt)){t._ensureFunction(e),t._ensureFunction(n);const r={},o=this.toArray();for(let t=0;t=e&&r(t[u],n)>0;)t[u+1]=t[u],u--;t[u+1]=n}}function o(t,e,n){const r=t[e];t[e]=t[n],t[n]=r}function u(t,e,n,r){const u=t[n+e>>1];for(;e<=n;){for(;r(t[e],u)<0;)e++;for(;r(t[n],u)>0;)n--;if(e=i?(t.right=f-1,f
2 | ///
3 | ///
4 |
5 | namespace Linqer {
6 |
7 | export interface Enumerable extends Iterable {
8 | /**
9 | * Returns a randomized sequence of items from an initial source
10 | * @returns shuffle
11 | */
12 | shuffle(): Enumerable;
13 | /**
14 | * implements random reservoir sampling of k items, with the option to specify a maximum limit for the items
15 | * @param k
16 | * @param limit
17 | * @returns sample
18 | */
19 | randomSample(k: number, limit: number): Enumerable;
20 | /**
21 | * Returns the count of the items in a sequence. Depending on the sequence type this iterates through it or not.
22 | * @returns count
23 | */
24 | count(): number;
25 | /**
26 | * returns the distinct values based on a hashing function
27 | *
28 | * @param {ISelector} hashFunc
29 | * @returns {Enumerable}
30 | * @memberof Enumerable
31 | */
32 | distinctByHash(hashFunc: ISelector): Enumerable;
33 | /**
34 | * returns the values that have different hashes from the items of the iterable provided
35 | *
36 | * @param {IterableType} iterable
37 | * @param {ISelector} hashFunc
38 | * @returns {Enumerable}
39 | * @memberof Enumerable
40 | */
41 | exceptByHash(iterable: IterableType, hashFunc: ISelector): Enumerable;
42 | /**
43 | * returns the values that have the same hashes as items of the iterable provided
44 | *
45 | * @param {IterableType} iterable
46 | * @param {ISelector} hashFunc
47 | * @returns {Enumerable}
48 | * @memberof Enumerable
49 | */
50 | intersectByHash(iterable: IterableType, hashFunc: ISelector): Enumerable;
51 | /**
52 | * returns the index of a value in an ordered enumerable or false if not found
53 | * WARNING: use the same comparer as the one used to order the enumerable. The algorithm assumes the enumerable is already sorted.
54 | *
55 | * @param {*} value
56 | * @param {IComparer} comparer
57 | * @returns {(number | boolean)}
58 | * @memberof Enumerable
59 | */
60 | binarySearch(value: any, comparer: IComparer): number | boolean;
61 | /**
62 | * joins each item of the enumerable with previous items from the same enumerable
63 | * @param offset
64 | * @param zipper
65 | * @returns lag
66 | */
67 | lag(offset: number, zipper: (item1: any, item2: any) => any): Enumerable;
68 | /**
69 | * joins each item of the enumerable with next items from the same enumerable
70 | *
71 | * @param {number} offset
72 | * @param {(item1: any, item2: any) => any} zipper
73 | * @returns {Enumerable}
74 | * @memberof Enumerable
75 | */
76 | lead(offset: number, zipper: (item1: any, item2: any) => any): Enumerable;
77 | /**
78 | * returns an enumerable of at least minLength, padding the end with a value or the result of a function
79 | *
80 | * @param {number} minLength
81 | * @param {(any | ((index: number) => any))} filler
82 | * @returns {Enumerable}
83 | * @memberof Enumerable
84 | */
85 | padEnd(minLength: number, filler: any | ((index: number) => any)): Enumerable;
86 | /**
87 | * returns an enumerable of at least minLength, padding the start with a value or the result of a function
88 | * if the enumerable cannot seek, then it will be iterated minLength time
89 | *
90 | * @param {number} minLength
91 | * @param {(any | ((index: number) => any))} filler
92 | * @returns {Enumerable}
93 | * @memberof Enumerable
94 | */
95 | padStart(minLength: number, filler: any | ((index: number) => any)): Enumerable;
96 | }
97 |
98 | /// randomizes the enumerable (partial Fisher-Yates)
99 | Enumerable.prototype.shuffle = function (): Enumerable {
100 | const self = this;
101 | function* gen() {
102 | const arr = self.toArray();
103 | const len = arr.length;
104 | let n = 0;
105 | while (n < len) {
106 | let k = n + Math.floor(Math.random() * (len - n));
107 | const value = arr[k];
108 | arr[k] = arr[n];
109 | arr[n] = value;
110 | n++;
111 | yield value;
112 | }
113 | }
114 | const result = Enumerable.from(gen);
115 | result._count = () => self.count();
116 | return result;
117 | };
118 |
119 | /// implements random reservoir sampling of k items, with the option to specify a maximum limit for the items
120 | Enumerable.prototype.randomSample = function (k: number, limit: number = Number.MAX_SAFE_INTEGER): Enumerable {
121 | let index = 0;
122 | const sample = [];
123 | _ensureInternalTryGetAt(this);
124 | if (this._canSeek) { // L algorithm
125 | const length = this.count();
126 | let index = 0;
127 | for (index = 0; index < k && index < limit && index < length; index++) {
128 | sample.push(this.elementAt(index));
129 | }
130 | let W = Math.exp(Math.log(Math.random()) / k);
131 | while (index < length && index < limit) {
132 | index += Math.floor(Math.log(Math.random()) / Math.log(1 - W)) + 1;
133 | if (index < length && index < limit) {
134 | sample[Math.floor(Math.random() * k)] = this.elementAt(index);
135 | W *= Math.exp(Math.log(Math.random()) / k);
136 | }
137 | }
138 | } else { // R algorithm
139 | for (const item of this) {
140 | if (index < k) {
141 | sample.push(item);
142 | } else {
143 | const j = Math.floor(Math.random() * index);
144 | if (j < k) {
145 | sample[j] = item;
146 | }
147 | }
148 | index++;
149 | if (index >= limit) break;
150 | }
151 | }
152 | return Enumerable.from(sample);
153 | }
154 |
155 | /// returns the distinct values based on a hashing function
156 | Enumerable.prototype.distinctByHash = function (hashFunc: ISelector): Enumerable {
157 | // this is much more performant than distinct with a custom comparer
158 | const self = this;
159 | const gen = function* () {
160 | const distinctValues = new Set();
161 | for (const item of self) {
162 | const size = distinctValues.size;
163 | distinctValues.add(hashFunc(item));
164 | if (size < distinctValues.size) {
165 | yield item;
166 | }
167 | }
168 | };
169 | return new Enumerable(gen);
170 | };
171 |
172 | /// returns the values that have different hashes from the items of the iterable provided
173 | Enumerable.prototype.exceptByHash = function (iterable: IterableType, hashFunc: ISelector): Enumerable {
174 | // this is much more performant than except with a custom comparer
175 | _ensureIterable(iterable);
176 | const self = this;
177 | const gen = function* () {
178 | const distinctValues = Enumerable.from(iterable).select(hashFunc).toSet();
179 | for (const item of self) {
180 | if (!distinctValues.has(hashFunc(item))) {
181 | yield item;
182 | }
183 | }
184 | };
185 | return new Enumerable(gen);
186 | };
187 |
188 | /// returns the values that have the same hashes as items of the iterable provided
189 | Enumerable.prototype.intersectByHash = function (iterable: IterableType, hashFunc: ISelector): Enumerable {
190 | // this is much more performant than intersect with a custom comparer
191 | _ensureIterable(iterable);
192 | const self = this;
193 | const gen = function* () {
194 | const distinctValues = Enumerable.from(iterable).select(hashFunc).toSet();
195 | for (const item of self) {
196 | if (distinctValues.has(hashFunc(item))) {
197 | yield item;
198 | }
199 | }
200 | };
201 | return new Enumerable(gen);
202 | };
203 |
204 | /// returns the index of a value in an ordered enumerable or false if not found
205 | /// WARNING: use the same comparer as the one used in the ordered enumerable. The algorithm assumes the enumerable is already sorted.
206 | Enumerable.prototype.binarySearch = function (value: any, comparer: IComparer = _defaultComparer): number | boolean {
207 | let enumerable: Enumerable = this.toList();
208 | let start = 0;
209 | let end = enumerable.count() - 1;
210 |
211 | while (start <= end) {
212 | const mid = (start + end) >> 1;
213 | const comp = comparer(enumerable.elementAt(mid), value);
214 | if (comp == 0) return mid;
215 | if (comp < 0) {
216 | start = mid + 1;
217 | } else {
218 | end = mid - 1;
219 | }
220 | }
221 |
222 | return false;
223 | };
224 |
225 | /// joins each item of the enumerable with previous items from the same enumerable
226 | Enumerable.prototype.lag = function (offset: number, zipper: (item1: any, item2: any) => any): Enumerable {
227 | if (!offset) {
228 | throw new Error('offset has to be positive');
229 | }
230 | if (offset < 0) {
231 | throw new Error('offset has to be positive. Use .lead if you want to join with next items');
232 | }
233 | if (!zipper) {
234 | zipper = (i1, i2) => [i1, i2];
235 | } else {
236 | _ensureFunction(zipper);
237 | }
238 | const self = this;
239 | _ensureInternalTryGetAt(this);
240 | // generator uses a buffer to hold all the items within the offset interval
241 | const gen = function* () {
242 | const buffer = Array(offset);
243 | let index = 0;
244 | for (const item of self) {
245 | const index2 = index - offset;
246 | const item2 = index2 < 0
247 | ? undefined
248 | : buffer[index2 % offset];
249 | yield zipper(item, item2);
250 | buffer[index % offset] = item;
251 | index++;
252 | }
253 | };
254 | const result = new Enumerable(gen);
255 | // count is the same as of the original enumerable
256 | result._count = () => {
257 | const count = self.count();
258 | if (!result._wasIterated) result._wasIterated = self._wasIterated;
259 | return count;
260 | };
261 | // seeking is possible only if the original was seekable
262 | if (self._canSeek) {
263 | result._canSeek = true;
264 | result._tryGetAt = (index: number) => {
265 | const val1 = self._tryGetAt!(index);
266 | const val2 = self._tryGetAt!(index - offset);
267 | if (val1) {
268 | return {
269 | value: zipper(
270 | val1.value,
271 | val2 ? val2.value : undefined
272 | )
273 | };
274 | }
275 | return null;
276 | };
277 | }
278 | return result;
279 | }
280 |
281 |
282 | /// joins each item of the enumerable with next items from the same enumerable
283 | Enumerable.prototype.lead = function (offset: number, zipper: (item1: any, item2: any) => any): Enumerable {
284 | if (!offset) {
285 | throw new Error('offset has to be positive');
286 | }
287 | if (offset < 0) {
288 | throw new Error('offset has to be positive. Use .lag if you want to join with previous items');
289 | }
290 | if (!zipper) {
291 | zipper = (i1, i2) => [i1, i2];
292 | } else {
293 | _ensureFunction(zipper);
294 | }
295 | const self = this;
296 | _ensureInternalTryGetAt(this);
297 | // generator uses a buffer to hold all the items within the offset interval
298 | const gen = function* () {
299 | const buffer = Array(offset);
300 | let index = 0;
301 | for (const item of self) {
302 | const index2 = index - offset;
303 | if (index2 >= 0) {
304 | const item2 = buffer[index2 % offset];
305 | yield zipper(item2, item);
306 | }
307 | buffer[index % offset] = item;
308 | index++;
309 | }
310 | for (let i = 0; i < offset; i++) {
311 | const item = buffer[(index + i) % offset];
312 | yield zipper(item, undefined);
313 | }
314 | };
315 | const result = new Enumerable(gen);
316 | // count is the same as of the original enumerable
317 | result._count = () => {
318 | const count = self.count();
319 | if (!result._wasIterated) result._wasIterated = self._wasIterated;
320 | return count;
321 | };
322 | // seeking is possible only if the original was seekable
323 | if (self._canSeek) {
324 | result._canSeek = true;
325 | result._tryGetAt = (index: number) => {
326 | const val1 = self._tryGetAt!(index);
327 | const val2 = self._tryGetAt!(index + offset);
328 | if (val1) {
329 | return {
330 | value: zipper(
331 | val1.value,
332 | val2 ? val2.value : undefined
333 | )
334 | };
335 | }
336 | return null;
337 | };
338 | }
339 | return result;
340 | }
341 |
342 | /// returns an enumerable of at least minLength, padding the end with a value or the result of a function
343 | Enumerable.prototype.padEnd = function (minLength: number, filler: any | ((index: number) => any)): Enumerable {
344 | if (minLength <= 0) {
345 | throw new Error('minLength has to be positive.');
346 | }
347 | let fillerFunc: (index: number) => any;
348 | if (typeof filler !== 'function') {
349 | fillerFunc = (index: number) => filler;
350 | } else {
351 | fillerFunc = filler;
352 | }
353 | const self = this;
354 | _ensureInternalTryGetAt(this);
355 | // generator iterates all elements,
356 | // then yields the result of the filler function until minLength items
357 | const gen = function* () {
358 | let index = 0;
359 | for (const item of self) {
360 | yield item;
361 | index++;
362 | }
363 | for (; index < minLength; index++) {
364 | yield fillerFunc(index);
365 | }
366 | };
367 | const result = new Enumerable(gen);
368 | // count is the maximum between minLength and the original count
369 | result._count = () => {
370 | const count = Math.max(minLength, self.count());
371 | if (!result._wasIterated) result._wasIterated = self._wasIterated;
372 | return count;
373 | };
374 | // seeking is possible if the original was seekable
375 | if (self._canSeek) {
376 | result._canSeek = true;
377 | result._tryGetAt = (index: number) => {
378 | const val = self._tryGetAt!(index);
379 | if (val) return val;
380 | if (index < minLength) {
381 | return { value: fillerFunc(index) };
382 | }
383 | return null;
384 | };
385 | }
386 | return result;
387 | }
388 |
389 |
390 | /// returns an enumerable of at least minLength, padding the start with a value or the result of a function
391 | /// if the enumerable cannot seek, then it will be iterated minLength time
392 | Enumerable.prototype.padStart = function (minLength: number, filler: any | ((index: number) => any)): Enumerable {
393 | if (minLength <= 0) {
394 | throw new Error('minLength has to be positive.');
395 | }
396 | let fillerFunc: (index: number) => any;
397 | if (typeof filler !== 'function') {
398 | fillerFunc = (index: number) => filler;
399 | } else {
400 | fillerFunc = filler;
401 | }
402 | const self = this;
403 | _ensureInternalTryGetAt(self);
404 | // generator needs a buffer to hold offset values
405 | // it yields values from the buffer when it overflows
406 | // or filler function results if the buffer is not full
407 | // after iterating the entire original enumerable
408 | const gen = function* () {
409 | const buffer = Array(minLength);
410 | let index = 0;
411 | const iterator = self[Symbol.iterator]();
412 | let flushed = false;
413 | let done = false;
414 | do {
415 | const val = iterator.next();
416 | done = !!val.done;
417 | if (!done) {
418 | buffer[index] = val.value;
419 | index++;
420 | }
421 | if (flushed && !done) {
422 | yield val.value;
423 | } else {
424 | if (done || index === minLength) {
425 | for (let i = 0; i < minLength - index; i++) {
426 | yield fillerFunc(i);
427 | }
428 | for (let i = 0; i < index; i++) {
429 | yield buffer[i];
430 | }
431 | flushed = true;
432 | }
433 | }
434 | } while (!done);
435 | };
436 | const result = new Enumerable(gen);
437 | // count is the max of minLength and the original count
438 | result._count = () => {
439 | const count = Math.max(minLength, self.count());
440 | if (!result._wasIterated) result._wasIterated = self._wasIterated;
441 | return count;
442 | };
443 | // seeking is possible only if the original was seekable
444 | if (self._canSeek) {
445 | result._canSeek = true;
446 | result._tryGetAt = (index: number) => {
447 | const count = self.count();
448 | const delta = minLength-count;
449 | if (delta<=0) {
450 | return self._tryGetAt!(index);
451 | }
452 | if (index}
9 | * @implements {IUsesQuickSort}
10 | */
11 | export class Enumerable implements Iterable, IUsesQuickSort {
12 | _src: IterableType;
13 | _generator: () => Iterator;
14 | _useQuickSort: boolean;
15 | // indicates that count and elementAt functions will not cause iterating the enumerable
16 | _canSeek: boolean;
17 | _count: null | (() => number);
18 | _tryGetAt: null | ((index: number) => { value: any } | null);
19 | // true if the enumerable was iterated at least once
20 | _wasIterated: boolean;
21 |
22 | /**
23 | * sort an array in place using the Enumerable sort algorithm (Quicksort)
24 | *
25 | * @static
26 | * @memberof Enumerable
27 | */
28 | static sort: (arr: any[], comparer?: IComparer) => any[];
29 |
30 | /**
31 | * You should never use this. Instead use Enumerable.from
32 | * @param {IterableType} src
33 | * @memberof Enumerable
34 | */
35 | constructor(src: IterableType) {
36 | _ensureIterable(src);
37 | this._src = src;
38 | const iteratorFunction: (() => Iterator) = (src as Iterable)[Symbol.iterator];
39 | // the generator is either the iterator of the source enumerable
40 | // or the generator function that was provided as the source itself
41 | if (iteratorFunction) {
42 | this._generator = iteratorFunction.bind(src);
43 | } else {
44 | this._generator = src as (() => Iterator);
45 | }
46 | // set sorting method on an enumerable and all the derived ones should inherit it
47 | // TODO: a better method of doing this
48 | this._useQuickSort = (src as IUsesQuickSort)._useQuickSort !== undefined
49 | ? (src as IUsesQuickSort)._useQuickSort
50 | : true;
51 | this._canSeek = false;
52 | this._count = null;
53 | this._tryGetAt = null;
54 | this._wasIterated = false;
55 | }
56 |
57 | /**
58 | * Wraps an iterable item into an Enumerable if it's not already one
59 | *
60 | * @static
61 | * @param {IterableType} iterable
62 | * @returns {Enumerable}
63 | * @memberof Enumerable
64 | */
65 | static from(iterable: IterableType): Enumerable {
66 | if (iterable instanceof Enumerable) return iterable;
67 | return new Enumerable(iterable);
68 | }
69 |
70 | /**
71 | * the Enumerable instance exposes the same iterator as the wrapped iterable or generator function
72 | *
73 | * @returns {Iterator}
74 | * @memberof Enumerable
75 | */
76 | [Symbol.iterator](): Iterator {
77 | this._wasIterated = true;
78 | return this._generator();
79 | }
80 |
81 | /**
82 | * returns an empty Enumerable
83 | *
84 | * @static
85 | * @returns {Enumerable}
86 | * @memberof Enumerable
87 | */
88 | static empty(): Enumerable {
89 | const result = new Enumerable([]);
90 | result._count = () => 0;
91 | result._tryGetAt = (index: number) => null;
92 | result._canSeek = true;
93 | return result;
94 | }
95 |
96 | /**
97 | * generates a sequence of integer numbers within a specified range.
98 | *
99 | * @static
100 | * @param {number} start
101 | * @param {number} count
102 | * @returns {Enumerable}
103 | * @memberof Enumerable
104 | */
105 | static range(start: number, count: number): Enumerable {
106 | const gen = function* () {
107 | for (let i = 0; i < count; i++) {
108 | yield start + i;
109 | }
110 | };
111 | const result = new Enumerable(gen);
112 | result._count = () => count;
113 | result._tryGetAt = index => {
114 | if (index >= 0 && index < count) return { value: start + index };
115 | return null;
116 | };
117 | result._canSeek = true;
118 | return result;
119 | }
120 |
121 | /**
122 | * Generates a sequence that contains one repeated value.
123 | *
124 | * @static
125 | * @param {*} item
126 | * @param {number} count
127 | * @returns {Enumerable}
128 | * @memberof Enumerable
129 | */
130 | static repeat(item: any, count: number): Enumerable {
131 | const gen = function* () {
132 | for (let i = 0; i < count; i++) {
133 | yield item;
134 | }
135 | };
136 | const result = new Enumerable(gen);
137 | result._count = () => count;
138 | result._tryGetAt = index => {
139 | if (index >= 0 && index < count) return { value: item };
140 | return null;
141 | };
142 | result._canSeek = true;
143 | return result;
144 | }
145 |
146 | /**
147 | * Same value as count(), but will throw an Error if enumerable is not seekable and has to be iterated to get the length
148 | */
149 | get length():number {
150 | _ensureInternalTryGetAt(this);
151 | if (!this._canSeek) throw new Error('Calling length on this enumerable will iterate it. Use count()');
152 | return this.count();
153 | }
154 |
155 | /**
156 | * Concatenates two sequences by appending iterable to the existing one.
157 | *
158 | * @param {IterableType} iterable
159 | * @returns {Enumerable}
160 | * @memberof Enumerable
161 | */
162 | concat(iterable: IterableType): Enumerable {
163 | _ensureIterable(iterable);
164 | const self: Enumerable = this;
165 | // the generator will iterate the enumerable first, then the iterable that was given as a parameter
166 | // this will be able to seek if both the original and the iterable derived enumerable can seek
167 | // the indexing function will get items from the first and then second enumerable without iteration
168 | const gen = function* () {
169 | for (const item of self) {
170 | yield item;
171 | }
172 | for (const item of Enumerable.from(iterable)) {
173 | yield item;
174 | }
175 | };
176 | const result = new Enumerable(gen);
177 | const other = Enumerable.from(iterable);
178 | result._count = () => self.count() + other.count();
179 | _ensureInternalTryGetAt(this);
180 | _ensureInternalTryGetAt(other);
181 | result._canSeek = self._canSeek && other._canSeek;
182 | if (self._canSeek) {
183 | result._tryGetAt = index => {
184 | return self._tryGetAt!(index) || other._tryGetAt!(index - self.count());
185 | };
186 | }
187 | return result;
188 | }
189 |
190 |
191 | /**
192 | * Returns the number of elements in a sequence.
193 | *
194 | * @returns {number}
195 | * @memberof Enumerable
196 | */
197 | count(): number {
198 | _ensureInternalCount(this);
199 | return this._count!();
200 | }
201 |
202 |
203 | /**
204 | * Returns distinct elements from a sequence.
205 | * WARNING: using a comparer makes this slower. Not specifying it uses a Set to determine distinctiveness.
206 | *
207 | * @param {IEqualityComparer} [equalityComparer=EqualityComparer.default]
208 | * @returns {Enumerable}
209 | * @memberof Enumerable
210 | */
211 | distinct(equalityComparer: IEqualityComparer = EqualityComparer.default): Enumerable {
212 | const self: Enumerable = this;
213 | // if the comparer function is not provided, a Set will be used to quickly determine distinctiveness
214 | const gen = equalityComparer === EqualityComparer.default
215 | ? function* () {
216 | const distinctValues = new Set();
217 | for (const item of self) {
218 | const size = distinctValues.size;
219 | distinctValues.add(item);
220 | if (size < distinctValues.size) {
221 | yield item;
222 | }
223 | }
224 | }
225 | // otherwise values will be compared with previous values ( O(n^2) )
226 | // use distinctByHash in Linqer.extra to use a hashing function ( O(n log n) )
227 | : function* () {
228 | const values = [];
229 | for (const item of self) {
230 | let unique = true;
231 | for (let i=0; i 0) agg.max = item;
363 | agg.count++;
364 | }
365 | return agg;
366 | }
367 |
368 | /**
369 | * Returns the minimum value in a sequence of values.
370 | * A custom function can be used to establish order (the result 0 means equal, 1 means larger, -1 means smaller)
371 | *
372 | * @param {IComparer} [comparer]
373 | * @returns {*}
374 | * @memberof Enumerable
375 | */
376 | min(comparer?: IComparer): any {
377 | const stats = this.stats(comparer);
378 | return stats.count === 0
379 | ? undefined
380 | : stats.min;
381 | }
382 |
383 |
384 | /**
385 | * Returns the maximum value in a sequence of values.
386 | * A custom function can be used to establish order (the result 0 means equal, 1 means larger, -1 means smaller)
387 | *
388 | * @param {IComparer} [comparer]
389 | * @returns {*}
390 | * @memberof Enumerable
391 | */
392 | max(comparer?: IComparer): any {
393 | const stats = this.stats(comparer);
394 | return stats.count === 0
395 | ? undefined
396 | : stats.max;
397 | }
398 |
399 |
400 | /**
401 | * Projects each element of a sequence into a new form.
402 | *
403 | * @param {ISelector} selector
404 | * @returns {Enumerable}
405 | * @memberof Enumerable
406 | */
407 | select(selector: ISelector): Enumerable {
408 | _ensureFunction(selector);
409 | const self: Enumerable = this;
410 | // the generator is applying the selector on all the items of the enumerable
411 | // the count of the resulting enumerable is the same as the original's
412 | // the indexer is the same as that of the original, with the selector applied on the value
413 | const gen = function* () {
414 | let index = 0;
415 | for (const item of self) {
416 | yield selector(item, index);
417 | index++;
418 | }
419 | };
420 | const result = new Enumerable(gen);
421 | _ensureInternalCount(this);
422 | result._count = this._count;
423 | _ensureInternalTryGetAt(self);
424 | result._canSeek = self._canSeek;
425 | result._tryGetAt = index => {
426 | const res = self._tryGetAt!(index);
427 | if (!res) return res;
428 | return { value: selector(res.value) };
429 | };
430 | return result;
431 | }
432 |
433 |
434 | /**
435 | * Bypasses a specified number of elements in a sequence and then returns the remaining elements.
436 | *
437 | * @param {number} nr
438 | * @returns {Enumerable}
439 | * @memberof Enumerable
440 | */
441 | skip(nr: number): Enumerable {
442 | const self: Enumerable = this;
443 | // the generator just enumerates the first nr numbers then starts yielding values
444 | // the count is the same as the original enumerable, minus the skipped items and at least 0
445 | // the indexer is the same as for the original, with an offset
446 | const gen = function* () {
447 | let nrLeft = nr;
448 | for (const item of self) {
449 | if (nrLeft > 0) {
450 | nrLeft--;
451 | } else {
452 | yield item;
453 | }
454 | }
455 | };
456 | const result = new Enumerable(gen);
457 |
458 | result._count = () => Math.max(0, self.count() - nr);
459 | _ensureInternalTryGetAt(this);
460 | result._canSeek = this._canSeek;
461 | result._tryGetAt = index => self._tryGetAt!(index + nr);
462 | return result;
463 | }
464 |
465 |
466 | /**
467 | * Takes start elements, ignores howmany elements, continues with the new items and continues with the original enumerable
468 | * Equivalent to the value of an array after performing splice on it with the same parameters
469 | * @param start
470 | * @param howmany
471 | * @param items
472 | * @returns splice
473 | */
474 | splice(start: number, howmany: number, ...newItems:any[]) : Enumerable {
475 | // tried to define length and splice so that this is seen as an Array-like object,
476 | // but it doesn't work on properties. length needs to be a field.
477 | return this.take(start).concat(newItems).concat(this.skip(start+howmany));
478 | }
479 |
480 | /**
481 | * Computes the sum of a sequence of numeric values.
482 | *
483 | * @returns {(number | undefined)}
484 | * @memberof Enumerable
485 | */
486 | sum(): number | undefined {
487 | const stats = this.sumAndCount();
488 | return stats.count === 0
489 | ? undefined
490 | : stats.sum;
491 | }
492 |
493 |
494 | /**
495 | * Computes the sum and count of a sequence of numeric values.
496 | *
497 | * @returns {{ sum: number, count: number }}
498 | * @memberof Enumerable
499 | */
500 | sumAndCount(): { sum: number, count: number } {
501 | const agg = {
502 | count: 0,
503 | sum: 0
504 | };
505 | for (const item of this) {
506 | agg.sum = agg.count === 0
507 | ? _toNumber(item)
508 | : agg.sum + _toNumber(item);
509 | agg.count++;
510 | }
511 | return agg;
512 | }
513 |
514 |
515 | /**
516 | * Returns a specified number of contiguous elements from the start of a sequence.
517 | *
518 | * @param {number} nr
519 | * @returns {Enumerable}
520 | * @memberof Enumerable
521 | */
522 | take(nr: number): Enumerable {
523 | const self: Enumerable = this;
524 | // the generator will stop after nr items yielded
525 | // the count is the maximum between the total count and nr
526 | // the indexer is the same, as long as it's not higher than nr
527 | const gen = function* () {
528 | let nrLeft = nr;
529 | for (const item of self) {
530 | if (nrLeft > 0) {
531 | yield item;
532 | nrLeft--;
533 | }
534 | if (nrLeft <= 0) {
535 | break;
536 | }
537 | }
538 | };
539 | const result = new Enumerable(gen);
540 |
541 | result._count = () => Math.min(nr, self.count());
542 | _ensureInternalTryGetAt(this);
543 | result._canSeek = self._canSeek;
544 | if (self._canSeek) {
545 | result._tryGetAt = index => {
546 | if (index >= nr) return null;
547 | return self._tryGetAt!(index);
548 | };
549 | }
550 | return result;
551 | }
552 |
553 |
554 | /**
555 | * creates an array from an Enumerable
556 | *
557 | * @returns {any[]}
558 | * @memberof Enumerable
559 | */
560 | toArray(): any[] {
561 | _ensureInternalTryGetAt(this);
562 | // this should be faster than Array.from(this)
563 | if (this._canSeek) {
564 | const arr = new Array(this.count());
565 | for (let i = 0; i < arr.length; i++) {
566 | arr[i] = this._tryGetAt!(i)?.value;
567 | }
568 | return arr;
569 | }
570 | // try to optimize the array growth by increasing it
571 | // by 64 every time it is needed
572 | const minIncrease = 64;
573 | let size = 0;
574 | const arr = [];
575 | for (const item of this) {
576 | if (size === arr.length) {
577 | arr.length += minIncrease;
578 | }
579 | arr[size] = item;
580 | size++;
581 | }
582 | arr.length = size;
583 | return arr;
584 | }
585 |
586 |
587 | /**
588 | * similar to toArray, but returns a seekable Enumerable (itself if already seekable) that can do count and elementAt without iterating
589 | *
590 | * @returns {Enumerable}
591 | * @memberof Enumerable
592 | */
593 | toList(): Enumerable {
594 | _ensureInternalTryGetAt(this);
595 | if (this._canSeek) return this;
596 | return Enumerable.from(this.toArray());
597 | }
598 |
599 | /**
600 | * Filters a sequence of values based on a predicate.
601 | *
602 | * @param {IFilter} condition
603 | * @returns {Enumerable}
604 | * @memberof Enumerable
605 | */
606 | where(condition: IFilter): Enumerable {
607 | _ensureFunction(condition);
608 | const self: Enumerable = this;
609 | // cannot imply the count or indexer from the condition
610 | // where will have to iterate through the whole thing
611 | const gen = function* () {
612 | let index = 0;
613 | for (const item of self) {
614 | if (condition(item, index)) {
615 | yield item;
616 | }
617 | index++;
618 | }
619 | };
620 | return new Enumerable(gen);
621 | }
622 | }
623 |
624 | // throw if src is not a generator function or an iteratable
625 | export function _ensureIterable(src: IterableType): void {
626 | if (src) {
627 | if ((src as Iterable)[Symbol.iterator]) return;
628 | if (typeof src === 'function' && (src as Function).constructor.name === 'GeneratorFunction') return;
629 | }
630 | throw new Error('the argument must be iterable!');
631 | }
632 | // throw if f is not a function
633 | export function _ensureFunction(f: Function): void {
634 | if (!f || typeof f !== 'function') throw new Error('the argument needs to be a function!');
635 | }
636 | // return Nan if this is not a number
637 | // different from Number(obj), which would cast strings to numbers
638 | function _toNumber(obj: any): number {
639 | return typeof obj === 'number'
640 | ? obj
641 | : Number.NaN;
642 | }
643 | // return the iterable if already an array or use Array.from to create one
644 | export function _toArray(iterable: IterableType) {
645 | if (!iterable) return [];
646 | if (Array.isArray(iterable)) return iterable;
647 | return Array.from(iterable);
648 | }
649 | // if the internal count function is not defined, set it to the most appropriate one
650 | export function _ensureInternalCount(enumerable: Enumerable) {
651 | if (enumerable._count) return;
652 | if (enumerable._src instanceof Enumerable) {
653 | // the count is the same as the underlying enumerable
654 | const innerEnumerable = enumerable._src as Enumerable;
655 | _ensureInternalCount(innerEnumerable);
656 | enumerable._count = () => innerEnumerable._count!();
657 | return;
658 | }
659 | const src = enumerable._src as any;
660 | // this could cause false positives, but if it has a numeric length or size, use it
661 | if (typeof src !== 'function' && typeof src.length === 'number') {
662 | enumerable._count = () => src.length;
663 | return;
664 | }
665 | if (typeof src.size === 'number') {
666 | enumerable._count = () => src.size;
667 | return;
668 | }
669 | // otherwise iterate the whole thing and count all items
670 | enumerable._count = () => {
671 | let x = 0;
672 | for (const item of enumerable) x++;
673 | return x;
674 | };
675 | }
676 | // ensure there is an internal indexer function adequate for this enumerable
677 | // this also determines if the enumerable can seek
678 | export function _ensureInternalTryGetAt(enumerable: Enumerable) {
679 | if (enumerable._tryGetAt) return;
680 | enumerable._canSeek = true;
681 | if (enumerable._src instanceof Enumerable) {
682 | // indexer and seekability is the same as for the underlying enumerable
683 | const innerEnumerable = enumerable._src as Enumerable;
684 | _ensureInternalTryGetAt(innerEnumerable);
685 | enumerable._tryGetAt = index => innerEnumerable._tryGetAt!(index);
686 | enumerable._canSeek = innerEnumerable._canSeek;
687 | return;
688 | }
689 | if (typeof enumerable._src === 'string') {
690 | // a string can be accessed by index
691 | enumerable._tryGetAt = index => {
692 | if (index < (enumerable._src as string).length) {
693 | return { value: (enumerable._src as string).charAt(index) };
694 | }
695 | return null;
696 | };
697 | return;
698 | }
699 | if (Array.isArray(enumerable._src)) {
700 | // an array can be accessed by index
701 | enumerable._tryGetAt = index => {
702 | if (index >= 0 && index < (enumerable._src as any[]).length) {
703 | return { value: (enumerable._src as any[])[index] };
704 | }
705 | return null;
706 | };
707 | return;
708 | }
709 | const src = enumerable._src as any;
710 | if (typeof enumerable._src !== 'function' && typeof src.length === 'number') {
711 | // try to access an object with a defined numeric length by indexing it
712 | // might cause false positives
713 | enumerable._tryGetAt = index => {
714 | if (index < src.length && typeof src[index] !== 'undefined') {
715 | return { value: src[index] };
716 | }
717 | return null;
718 | };
719 | return;
720 | }
721 | enumerable._canSeek = false;
722 | // TODO other specialized types? objects, maps, sets?
723 | enumerable._tryGetAt = index => {
724 | let x = 0;
725 | for (const item of enumerable) {
726 | if (index === x) return { value: item };
727 | x++;
728 | }
729 | return null;
730 | }
731 | }
732 |
733 | /**
734 | * an extended iterable type that also supports generator functions
735 | */
736 | export type IterableType = Iterable | (() => Iterator) | Enumerable;
737 |
738 | /**
739 | * A comparer function to be used in sorting
740 | */
741 | export type IComparer = (item1: any, item2: any) => -1 | 0 | 1;
742 | /**
743 | * A selector function to be used in mapping
744 | */
745 | export type ISelector = (item: any, index?: number) => T;
746 | /**
747 | * A filter function
748 | */
749 | export type IFilter = ISelector;
750 |
751 | /**
752 | * The default comparer function between two items
753 | * @param item1
754 | * @param item2
755 | */
756 | export const _defaultComparer: IComparer = (item1, item2) => {
757 | if (item1 > item2) return 1;
758 | if (item1 < item2) return -1;
759 | return 0;
760 | };
761 |
762 | /**
763 | * Interface for an equality comparer
764 | */
765 | export type IEqualityComparer = (item1: any, item2: any) => boolean;
766 |
767 | /**
768 | * Predefined equality comparers
769 | * default is the equivalent of ==
770 | * exact is the equivalent of ===
771 | */
772 | export const EqualityComparer = {
773 | default: (item1: any, item2: any) => item1 == item2,
774 | exact: (item1: any, item2: any) => item1 === item2,
775 | };
776 |
777 | // used to access the variable determining if
778 | // an enumerable should be ordered using Quicksort or not
779 | interface IUsesQuickSort {
780 | _useQuickSort: boolean;
781 | }
782 | }
--------------------------------------------------------------------------------
/LInQer.Enumerable.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | namespace Linqer {
4 |
5 | export interface Enumerable extends Iterable {
6 | /**
7 | * Applies an accumulator function over a sequence.
8 | * The specified seed value is used as the initial accumulator value, and the specified function is used to select the result value.
9 | *
10 | * @param {*} accumulator
11 | * @param {(acc: any, item: any) => any} aggregator
12 | * @returns {*}
13 | * @memberof Enumerable
14 | */
15 | aggregate(accumulator: any, aggregator: (acc: any, item: any) => any): any;
16 | /**
17 | * Determines whether all elements of a sequence satisfy a condition.
18 | * @param condition
19 | * @returns true if all
20 | */
21 | all(condition: IFilter): boolean;
22 | /**
23 | * Determines whether any element of a sequence exists or satisfies a condition.
24 | *
25 | * @param {IFilter} condition
26 | * @returns {boolean}
27 | * @memberof Enumerable
28 | */
29 | any(condition: IFilter): boolean;
30 | /**
31 | * Appends a value to the end of the sequence.
32 | *
33 | * @param {*} item
34 | * @returns {Enumerable}
35 | * @memberof Enumerable
36 | */
37 | append(item: any): Enumerable;
38 | /**
39 | * Computes the average of a sequence of numeric values.
40 | *
41 | * @returns {(number | undefined)}
42 | * @memberof Enumerable
43 | */
44 | average(): number | undefined;
45 | /**
46 | * Returns itself
47 | *
48 | * @returns {Enumerable}
49 | * @memberof Enumerable
50 | */
51 | asEnumerable(): Enumerable;
52 | /**
53 | * Checks the elements of a sequence based on their type
54 | * If type is a string, it will check based on typeof, else it will use instanceof.
55 | * Throws if types are different.
56 | * @param {(string | Function)} type
57 | * @returns {Enumerable}
58 | * @memberof Enumerable
59 | */
60 | cast(type: string | Function): Enumerable;
61 | /**
62 | * Determines whether a sequence contains a specified element.
63 | * A custom function can be used to determine equality between elements.
64 | *
65 | * @param {*} item
66 | * @param {IEqualityComparer} equalityComparer
67 | * @returns {boolean}
68 | * @memberof Enumerable
69 | */
70 | contains(item: any, equalityComparer: IEqualityComparer): boolean;
71 |
72 | defaultIfEmpty(): never;
73 |
74 | /**
75 | * Produces the set difference of two sequences
76 | * WARNING: using the comparer is slower
77 | *
78 | * @param {IterableType} iterable
79 | * @param {IEqualityComparer} equalityComparer
80 | * @returns {Enumerable}
81 | * @memberof Enumerable
82 | */
83 | except(iterable: IterableType, equalityComparer: IEqualityComparer): Enumerable;
84 | /**
85 | * Produces the set intersection of two sequences.
86 | * WARNING: using a comparer is slower
87 | *
88 | * @param {IterableType} iterable
89 | * @param {IEqualityComparer} equalityComparer
90 | * @returns {Enumerable}
91 | * @memberof Enumerable
92 | */
93 | intersect(iterable: IterableType, equalityComparer: IEqualityComparer): Enumerable;
94 | /**
95 | * Same as count
96 | *
97 | * @returns {number}
98 | * @memberof Enumerable
99 | */
100 | longCount(): number;
101 | /**
102 | * Filters the elements of a sequence based on their type
103 | * If type is a string, it will filter based on typeof, else it will use instanceof
104 | *
105 | * @param {(string | Function)} type
106 | * @returns {Enumerable}
107 | * @memberof Enumerable
108 | */
109 | ofType(type: string | Function): Enumerable;
110 | /**
111 | * Adds a value to the beginning of the sequence.
112 | *
113 | * @param {*} item
114 | * @returns {Enumerable}
115 | * @memberof Enumerable
116 | */
117 | prepend(item: any): Enumerable;
118 | /**
119 | * Inverts the order of the elements in a sequence.
120 | *
121 | * @returns {Enumerable}
122 | * @memberof Enumerable
123 | */
124 | reverse(): Enumerable;
125 | /**
126 | * Projects each element of a sequence to an iterable and flattens the resulting sequences into one sequence.
127 | *
128 | * @param {ISelector} selector
129 | * @returns {Enumerable}
130 | * @memberof Enumerable
131 | */
132 | selectMany(selector: ISelector): Enumerable;
133 | /**
134 | * Determines whether two sequences are equal and in the same order according to an optional equality comparer.
135 | *
136 | * @param {IterableType} iterable
137 | * @param {IEqualityComparer} equalityComparer
138 | * @returns {boolean}
139 | * @memberof Enumerable
140 | */
141 | sequenceEqual(iterable: IterableType, equalityComparer: IEqualityComparer): boolean;
142 | /**
143 | * Returns the single element of a sequence and throws if it doesn't have exactly one
144 | *
145 | * @returns {*}
146 | * @memberof Enumerable
147 | */
148 | single(): any;
149 | /**
150 | * Returns the single element of a sequence or undefined if none found. It throws if the sequence contains multiple items.
151 | *
152 | * @returns {(any | undefined)}
153 | * @memberof Enumerable
154 | */
155 | singleOrDefault(): any | undefined;
156 | /**
157 | * Returns a new enumerable collection that contains the elements from source with the last nr elements of the source collection omitted.
158 | *
159 | * @param {number} nr
160 | * @returns {Enumerable}
161 | * @memberof Enumerable
162 | */
163 | skipLast(nr: number): Enumerable;
164 | /**
165 | * Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.
166 | *
167 | * @param {IFilter} condition
168 | * @returns {Enumerable}
169 | * @memberof Enumerable
170 | */
171 | skipWhile(condition: IFilter): Enumerable;
172 |
173 | /**
174 | * Selects the elements starting at the given start argument, and ends at, but does not include, the given end argument.
175 | * @param start
176 | * @param end
177 | * @returns slice
178 | */
179 | slice(start: number | undefined, end: number | undefined) : Enumerable;
180 |
181 | /**
182 | * Returns a new enumerable collection that contains the last nr elements from source.
183 | *
184 | * @param {number} nr
185 | * @returns {Enumerable}
186 | * @memberof Enumerable
187 | */
188 | takeLast(nr: number): Enumerable;
189 | /**
190 | * Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements.
191 | *
192 | * @param {IFilter} condition
193 | * @returns {Enumerable}
194 | * @memberof Enumerable
195 | */
196 | takeWhile(condition: IFilter): Enumerable;
197 | toDictionary(): never;
198 | /**
199 | * creates a Map from an Enumerable
200 | *
201 | * @param {ISelector} keySelector
202 | * @param {ISelector} valueSelector
203 | * @returns {Map}
204 | * @memberof Enumerable
205 | */
206 | toMap(keySelector: ISelector, valueSelector: ISelector): Map;
207 | /**
208 | * creates an object from an Enumerable
209 | *
210 | * @param {ISelector} keySelector
211 | * @param {ISelector} valueSelector
212 | * @returns {{ [key: string]: any }}
213 | * @memberof Enumerable
214 | */
215 | toObject(keySelector: ISelector, valueSelector: ISelector): { [key: string]: any };
216 | toHashSet(): never;
217 | /**
218 | * creates a Set from an enumerable
219 | *
220 | * @returns {Set}
221 | * @memberof Enumerable
222 | */
223 | toSet(): Set;
224 | /**
225 | * Produces the set union of two sequences.
226 | *
227 | * @param {IterableType} iterable
228 | * @param {IEqualityComparer} equalityComparer
229 | * @returns {Enumerable}
230 | * @memberof Enumerable
231 | */
232 | union(iterable: IterableType, equalityComparer: IEqualityComparer): Enumerable;
233 | /**
234 | * Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
235 | *
236 | * @param {IterableType} iterable
237 | * @param {(item1: any, item2: any, index: number) => any} zipper
238 | * @returns {*}
239 | * @memberof Enumerable
240 | */
241 | zip(iterable: IterableType, zipper: (item1: any, item2: any, index: number) => any): any;
242 |
243 | }
244 |
245 | /// Applies an accumulator function over a sequence.
246 | /// The specified seed value is used as the initial accumulator value, and the specified function is used to select the result value.
247 | Enumerable.prototype.aggregate = function (accumulator: any, aggregator: (acc: any, item: any) => any): any {
248 | _ensureFunction(aggregator);
249 | for (const item of this) {
250 | accumulator = aggregator(accumulator, item);
251 | }
252 | return accumulator;
253 | }
254 |
255 | /// Determines whether all elements of a sequence satisfy a condition.
256 | Enumerable.prototype.all = function (condition: IFilter): boolean {
257 | _ensureFunction(condition);
258 | return !this.any(x => !condition(x));
259 | }
260 |
261 | /// Determines whether any element of a sequence exists or satisfies a condition.
262 | Enumerable.prototype.any = function (condition: IFilter): boolean {
263 | _ensureFunction(condition);
264 | let index = 0;
265 | for (const item of this) {
266 | if (condition(item, index)) return true;
267 | index++;
268 | }
269 | return false;
270 | }
271 |
272 | /// Appends a value to the end of the sequence.
273 | Enumerable.prototype.append = function (item: any): Enumerable {
274 | return this.concat([item]);
275 | }
276 |
277 | /// Computes the average of a sequence of numeric values.
278 | Enumerable.prototype.average = function (): number | undefined {
279 | const stats = this.sumAndCount();
280 | return stats.count === 0
281 | ? undefined
282 | : stats.sum / stats.count;
283 | }
284 |
285 | /// Returns the same enumerable
286 | Enumerable.prototype.asEnumerable = function (): Enumerable {
287 | return this;
288 | }
289 |
290 | /// Checks the elements of a sequence based on their type
291 | /// If type is a string, it will check based on typeof, else it will use instanceof.
292 | /// Throws if types are different.
293 | Enumerable.prototype.cast = function (type: string | Function): Enumerable {
294 | const f: ((x: any) => boolean) = typeof type === 'string'
295 | ? x => typeof x === type
296 | : x => x instanceof type;
297 | return this.select(item => {
298 | if (!f(item)) throw new Error(item + ' not of type ' + type);
299 | return item;
300 | });
301 | }
302 |
303 | /// Determines whether a sequence contains a specified element.
304 | /// A custom function can be used to determine equality between elements.
305 | Enumerable.prototype.contains = function (item: any, equalityComparer: IEqualityComparer = EqualityComparer.default): boolean {
306 | _ensureFunction(equalityComparer);
307 | return this.any(x => equalityComparer(x, item));
308 | }
309 |
310 | Enumerable.prototype.defaultIfEmpty = function (): never {
311 | throw new Error('defaultIfEmpty not implemented for Javascript');
312 | }
313 |
314 | /// Produces the set difference of two sequences WARNING: using the comparer is slower
315 | Enumerable.prototype.except = function (iterable: IterableType, equalityComparer: IEqualityComparer = EqualityComparer.default): Enumerable {
316 | _ensureIterable(iterable);
317 | const self: Enumerable = this;
318 | // use a Set for performance if the comparer is not set
319 | const gen = equalityComparer === EqualityComparer.default
320 | ? function* () {
321 | const distinctValues = Enumerable.from(iterable).toSet();
322 | for (const item of self) {
323 | if (!distinctValues.has(item)) yield item;
324 | }
325 | }
326 | // use exceptByHash from Linqer.extra for better performance
327 | : function* () {
328 | const values = _toArray(iterable);
329 | for (const item of self) {
330 | let unique = true;
331 | for (let i=0; i typeof x === type
383 | : x => x instanceof type;
384 | return this.where(condition);
385 | }
386 |
387 | /// Adds a value to the beginning of the sequence.
388 | Enumerable.prototype.prepend = function (item: any): Enumerable {
389 | return new Enumerable([item]).concat(this);
390 | }
391 |
392 | /// Inverts the order of the elements in a sequence.
393 | Enumerable.prototype.reverse = function (): Enumerable {
394 | _ensureInternalTryGetAt(this);
395 | const self: Enumerable = this;
396 | // if it can seek, just read the enumerable backwards
397 | const gen = this._canSeek
398 | ? function* () {
399 | const length = self.count();
400 | for (let index = length - 1; index >= 0; index--) {
401 | yield self.elementAt(index);
402 | }
403 | }
404 | // else enumerate it all into an array, then read it backwards
405 | : function* () {
406 | const arr = self.toArray();
407 | for (let index = arr.length - 1; index >= 0; index--) {
408 | yield arr[index];
409 | }
410 | };
411 | // the count is the same when reversed
412 | const result = new Enumerable(gen);
413 | _ensureInternalCount(this);
414 | result._count = this._count;
415 | _ensureInternalTryGetAt(this);
416 | // have a custom indexer only if the original enumerable could seek
417 | if (this._canSeek) {
418 | const self = this;
419 | result._canSeek = true;
420 | result._tryGetAt = index => self._tryGetAt!(self.count() - index - 1);
421 | }
422 | return result;
423 | }
424 |
425 | /// Projects each element of a sequence to an iterable and flattens the resulting sequences into one sequence.
426 | Enumerable.prototype.selectMany = function (selector: ISelector): Enumerable {
427 | if (typeof selector !== 'undefined') {
428 | _ensureFunction(selector);
429 | } else {
430 | selector = x => x;
431 | }
432 | const self: Enumerable = this;
433 | const gen = function* () {
434 | let index = 0;
435 | for (const item of self) {
436 | const iter = selector(item, index);
437 | _ensureIterable(iter);
438 | for (const child of iter) {
439 | yield child;
440 | }
441 | index++;
442 | }
443 | };
444 | return new Enumerable(gen);
445 | }
446 |
447 | /// Determines whether two sequences are equal and in the same order according to an equality comparer.
448 | Enumerable.prototype.sequenceEqual = function (iterable: IterableType, equalityComparer: IEqualityComparer = EqualityComparer.default): boolean {
449 | _ensureIterable(iterable);
450 | _ensureFunction(equalityComparer);
451 | const iterator1 = this[Symbol.iterator]();
452 | const iterator2 = Enumerable.from(iterable)[Symbol.iterator]();
453 | let done = false;
454 | do {
455 | const val1 = iterator1.next();
456 | const val2 = iterator2.next();
457 | const equal = (val1.done && val2.done) || (!val1.done && !val2.done && equalityComparer(val1.value, val2.value));
458 | if (!equal) return false;
459 | done = !!val1.done;
460 | } while (!done);
461 | return true;
462 | }
463 |
464 | /// Returns the single element of a sequence and throws if it doesn't have exactly one
465 | Enumerable.prototype.single = function (): any {
466 | const iterator = this[Symbol.iterator]();
467 | let val = iterator.next();
468 | if (val.done) throw new Error('Sequence contains no elements');
469 | const result = val.value;
470 | val = iterator.next();
471 | if (!val.done) throw new Error('Sequence contains more than one element');
472 | return result;
473 | }
474 |
475 | /// Returns the single element of a sequence or undefined if none found. It throws if the sequence contains multiple items.
476 | Enumerable.prototype.singleOrDefault = function (): any | undefined {
477 | const iterator = this[Symbol.iterator]();
478 | let val = iterator.next();
479 | if (val.done) return undefined;
480 | const result = val.value;
481 | val = iterator.next();
482 | if (!val.done) throw new Error('Sequence contains more than one element');
483 | return result;
484 | }
485 |
486 | /// Selects the elements starting at the given start argument, and ends at, but does not include, the given end argument.
487 | Enumerable.prototype.slice = function (start: number = 0, end: number | undefined): Enumerable {
488 | let enumerable: Enumerable = this;
489 | // when the end is defined and positive and start is negative,
490 | // the only way to compute the last index is to know the count
491 | if (end !== undefined && end >= 0 && (start || 0) < 0) {
492 | enumerable = enumerable.toList();
493 | start = enumerable.count() + start;
494 | }
495 | if (start !== 0) {
496 | if (start > 0) {
497 | enumerable = enumerable.skip(start);
498 | } else {
499 | enumerable = enumerable.takeLast(-start);
500 | }
501 | }
502 | if (end !== undefined) {
503 | if (end >= 0) {
504 | enumerable = enumerable.take(end - start);
505 | } else {
506 | enumerable = enumerable.skipLast(-end);
507 | }
508 | }
509 | return enumerable;
510 | }
511 |
512 | /// Returns a new enumerable collection that contains the elements from source with the last nr elements of the source collection omitted.
513 | Enumerable.prototype.skipLast = function (nr: number): Enumerable {
514 | const self: Enumerable = this;
515 | // the generator is using a buffer to cache nr values
516 | // and only yields the values that overflow from it
517 | const gen = function* () {
518 | let nrLeft = nr;
519 | const buffer = Array(nrLeft);
520 | let index = 0;
521 | let offset = 0;
522 | for (const item of self) {
523 | const value = buffer[index - offset];
524 | buffer[index - offset] = item;
525 | index++;
526 | if (index - offset >= nrLeft) {
527 | offset += nrLeft;
528 | }
529 | if (index > nrLeft) {
530 | yield value;
531 | }
532 | }
533 | buffer.length = 0;
534 | };
535 | const result = new Enumerable(gen);
536 |
537 | // the count is the original count minus the skipped items and at least 0
538 | result._count = () => Math.max(0, self.count() - nr);
539 | _ensureInternalTryGetAt(this);
540 | result._canSeek = this._canSeek;
541 | // it has an indexer only if the original enumerable can seek
542 | if (this._canSeek) {
543 | result._tryGetAt = index => {
544 | if (index >= result.count()) return null;
545 | return self._tryGetAt!(index);
546 | }
547 | }
548 | return result;
549 | }
550 |
551 |
552 | /// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.
553 | Enumerable.prototype.skipWhile = function (condition: IFilter): Enumerable {
554 | _ensureFunction(condition);
555 | const self: Enumerable = this;
556 | let skip = true;
557 | const gen = function* () {
558 | let index = 0;
559 | for (const item of self) {
560 | if (skip && !condition(item, index)) {
561 | skip = false;
562 | }
563 | if (!skip) {
564 | yield item;
565 | }
566 | index++;
567 | }
568 | };
569 | return new Enumerable(gen);
570 | }
571 |
572 | /// Returns a new enumerable collection that contains the last nr elements from source.
573 | Enumerable.prototype.takeLast = function (nr: number): Enumerable {
574 | _ensureInternalTryGetAt(this);
575 | const self: Enumerable = this;
576 | const gen = this._canSeek
577 | // taking the last items is easy if the enumerable can seek
578 | ? function* () {
579 | let nrLeft = nr;
580 | const length = self.count();
581 | for (let index = length - nrLeft; index < length; index++) {
582 | yield self.elementAt(index);
583 | }
584 | }
585 | // else the generator uses a buffer to fill with values
586 | // and yields them after the entire thing has been iterated
587 | : function* () {
588 | let nrLeft = nr;
589 | let index = 0;
590 | const buffer = Array(nrLeft);
591 | for (const item of self) {
592 | buffer[index % nrLeft] = item;
593 | index++;
594 | }
595 | for (let i = 0; i < nrLeft && i < index; i++) {
596 | yield buffer[(index + i) % nrLeft];
597 | }
598 | };
599 | const result = new Enumerable(gen);
600 |
601 | // the count is the minimum between nr and the enumerable count
602 | result._count = () => Math.min(nr, self.count());
603 | result._canSeek = self._canSeek;
604 | // this can seek only if the original enumerable could seek
605 | if (self._canSeek) {
606 | result._tryGetAt = index => {
607 | if (index < 0 || index >= result.count()) return null;
608 | return self._tryGetAt!(self.count() - nr + index);
609 | };
610 | }
611 | return result;
612 | }
613 |
614 | /// Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements.
615 | Enumerable.prototype.takeWhile = function (condition: IFilter): Enumerable {
616 | _ensureFunction(condition);
617 | const self: Enumerable = this;
618 | const gen = function* () {
619 | let index = 0;
620 | for (const item of self) {
621 | if (condition(item, index)) {
622 | yield item;
623 | } else {
624 | break;
625 | }
626 | index++;
627 | }
628 | };
629 | return new Enumerable(gen);
630 | }
631 |
632 | Enumerable.prototype.toDictionary = function (): never {
633 | throw new Error('use toMap or toObject instead of toDictionary');
634 | }
635 |
636 | /// creates a map from an Enumerable
637 | Enumerable.prototype.toMap = function (keySelector: ISelector, valueSelector: ISelector = x => x): Map {
638 | _ensureFunction(keySelector);
639 | _ensureFunction(valueSelector);
640 | const result = new Map();
641 | let index = 0;
642 | for (const item of this) {
643 | result.set(keySelector(item, index), valueSelector(item, index));
644 | index++;
645 | }
646 | return result;
647 | }
648 |
649 | /// creates an object from an enumerable
650 | Enumerable.prototype.toObject = function (keySelector: ISelector, valueSelector: ISelector = x => x): { [key: string]: any } {
651 | _ensureFunction(keySelector);
652 | _ensureFunction(valueSelector);
653 | const result: { [key: string]: any } = {};
654 | let index = 0;
655 | for (const item of this) {
656 | result[keySelector(item, index)] = valueSelector(item);
657 | index++;
658 | }
659 | return result;
660 | }
661 |
662 | Enumerable.prototype.toHashSet = function (): never {
663 | throw new Error('use toSet instead of toHashSet');
664 | }
665 |
666 | /// creates a set from an enumerable
667 | Enumerable.prototype.toSet = function (): Set {
668 | const result = new Set();
669 | for (const item of this) {
670 | result.add(item);
671 | }
672 | return result;
673 | }
674 |
675 | /// Produces the set union of two sequences.
676 | Enumerable.prototype.union = function (iterable: IterableType, equalityComparer: IEqualityComparer = EqualityComparer.default): Enumerable {
677 | _ensureIterable(iterable);
678 | return this.concat(iterable).distinct(equalityComparer);
679 | }
680 |
681 | /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
682 | Enumerable.prototype.zip = function (iterable: IterableType, zipper: (item1: any, item2: any, index: number) => any): any {
683 | _ensureIterable(iterable);
684 | if (!zipper) {
685 | zipper = (i1,i2)=>[i1,i2];
686 | } else {
687 | _ensureFunction(zipper);
688 | }
689 | const self: Enumerable = this;
690 | const gen = function* () {
691 | let index = 0;
692 | const iterator1 = self[Symbol.iterator]();
693 | const iterator2 = Enumerable.from(iterable)[Symbol.iterator]();
694 | let done = false;
695 | do {
696 | const val1 = iterator1.next();
697 | const val2 = iterator2.next();
698 | done = !!(val1.done || val2.done);
699 | if (!done) {
700 | yield zipper(val1.value, val2.value, index);
701 | }
702 | index++;
703 | } while (!done);
704 | };
705 | return new Enumerable(gen);
706 | }
707 | }
--------------------------------------------------------------------------------