• WPS JSA 宏编程(JS):5.推荐一个外部模块 linq.js


    linq.js 是一个开源的包,我下载自 https://github.com/mihaifm/linq,大家如果需要可由此地下载,其代码如下:

       1 /*--------------------------------------------------------------------------
       2  * linq.js - LINQ for JavaScript
       3  * licensed under MIT License
       4  *------------------------------------------------------------------------*/
       5 
       6 (function (root, undefined) {
       7     // ReadOnly Function
       8     var Functions = {
       9         Identity: function (x) { return x; },
      10         True: function () { return true; },
      11         Blank: function () { }
      12     };
      13 
      14     // const Type
      15     var Types = {
      16         Boolean: typeof true,
      17         Number: typeof 0,
      18         String: typeof "",
      19         Object: typeof {},
      20         Undefined: typeof undefined,
      21         Function: typeof function () { }
      22     };
      23 
      24     // createLambda cache
      25     var funcCache = { "": Functions.Identity };
      26 
      27     // private utility methods
      28     var Utils = {
      29         // Create anonymous function from lambda expression string
      30         createLambda: function (expression) {
      31             if (expression == null) return Functions.Identity;
      32             if (typeof expression === Types.String) {
      33                 // get from cache
      34                 var f = funcCache[expression];
      35                 if (f != null) {
      36                     return f;
      37                 }
      38 
      39                 if (expression.indexOf("=>") === -1) {
      40                     var regexp = new RegExp("[$]+", "g");
      41 
      42                     var maxLength = 0;
      43                     var match;
      44                     while ((match = regexp.exec(expression)) != null) {
      45                         var paramNumber = match[0].length;
      46                         if (paramNumber > maxLength) {
      47                             maxLength = paramNumber;
      48                         }
      49                     }
      50 
      51                     var argArray = [];
      52                     for (var i = 1; i <= maxLength; i++) {
      53                         var dollar = "";
      54                         for (var j = 0; j < i; j++) {
      55                             dollar += "$";
      56                         }
      57                         argArray.push(dollar);
      58                     }
      59 
      60                     var args = Array.prototype.join.call(argArray, ",");
      61 
      62                     f = new Function(args, "return " + expression);
      63                     funcCache[expression] = f;
      64                     return f;
      65                 }
      66                 else {
      67                     var expr = expression.match(/^[(s]*([^()]*?)[)s]*=>(.*)/);
      68                     f = new Function(expr[1], (expr[2].match(/return/) ? expr[2] : "return " + expr[2]));
      69                     funcCache[expression] = f;
      70                     return f;
      71                 }
      72             }
      73             return expression;
      74         },
      75 
      76         isIEnumerable: function (obj) {
      77             if (typeof Enumerator !== Types.Undefined) {
      78                 try {
      79                     new Enumerator(obj); // check JScript(IE)'s Enumerator
      80                     return true;
      81                 }
      82                 catch (e) { }
      83             }
      84 
      85             return false;
      86         },
      87 
      88         // IE8's defineProperty is defined but cannot use, therefore check defineProperties
      89         defineProperty: (Object.defineProperties != null)
      90             ? function (target, methodName, value) {
      91                 Object.defineProperty(target, methodName, {
      92                     enumerable: false,
      93                     configurable: true,
      94                     writable: true,
      95                     value: value
      96                 })
      97             }
      98             : function (target, methodName, value) {
      99                 target[methodName] = value;
     100             },
     101 
     102         compare: function (a, b) {
     103             return (a === b) ? 0
     104                  : (a > b) ? 1
     105                  : -1;
     106         },
     107 
     108         dispose: function (obj) {
     109             if (obj != null) obj.dispose();
     110         },
     111 
     112         hasNativeIteratorSupport: function () {
     113             return typeof Symbol !== 'undefined' && typeof Symbol.iterator !== 'undefined';
     114         }
     115     };
     116 
     117     // IEnumerator State
     118     var State = { Before: 0, Running: 1, After: 2 };
     119 
     120     // "Enumerator" is conflict JScript's "Enumerator"
     121     var IEnumerator = function (initialize, tryGetNext, dispose) {
     122         var yielder = new Yielder();
     123         var state = State.Before;
     124 
     125         this.current = yielder.current;
     126 
     127         this.moveNext = function () {
     128             try {
     129                 switch (state) {
     130                     case State.Before:
     131                         state = State.Running;
     132                         initialize();
     133                         // fall through
     134                     case State.Running:
     135                         if (tryGetNext.apply(yielder)) {
     136                             return true;
     137                         }
     138                         else {
     139                             this.dispose();
     140                             return false;
     141                         }
     142                     case State.After:
     143                         return false;
     144                 }
     145             }
     146             catch (e) {
     147                 this.dispose();
     148                 throw e;
     149             }
     150         };
     151 
     152         this.dispose = function () {
     153             if (state != State.Running) return;
     154 
     155             try {
     156                 dispose();
     157             }
     158             finally {
     159                 state = State.After;
     160             }
     161         };
     162     };
     163 
     164     // for tryGetNext
     165     var Yielder = function () {
     166         var current = null;
     167         this.current = function () { return current; };
     168         this.yieldReturn = function (value) {
     169             current = value;
     170             return true;
     171         };
     172         this.yieldBreak = function () {
     173             return false;
     174         };
     175     };
     176 
     177     // Enumerable constuctor
     178     var Enumerable = function (getEnumerator) {
     179         this.getEnumerator = getEnumerator;
     180     };
     181 
     182     // Utility
     183 
     184     Enumerable.Utils = {}; // container
     185 
     186     Enumerable.Utils.createLambda = function (expression) {
     187         return Utils.createLambda(expression);
     188     };
     189 
     190     Enumerable.Utils.createEnumerable = function (getEnumerator) {
     191         return new Enumerable(getEnumerator);
     192     };
     193 
     194     Enumerable.Utils.createEnumerator = function (initialize, tryGetNext, dispose) {
     195         return new IEnumerator(initialize, tryGetNext, dispose);
     196     };
     197 
     198     Enumerable.Utils.extendTo = function (type) {
     199         var typeProto = type.prototype;
     200         var enumerableProto;
     201 
     202         if (type === Array) {
     203             enumerableProto = ArrayEnumerable.prototype;
     204             Utils.defineProperty(typeProto, "getSource", function () {
     205                 return this;
     206             });
     207         }
     208         else {
     209             enumerableProto = Enumerable.prototype;
     210             Utils.defineProperty(typeProto, "getEnumerator", function () {
     211                 return Enumerable.from(this).getEnumerator();
     212             });
     213         }
     214 
     215         for (var methodName in enumerableProto) {
     216             var func = enumerableProto[methodName];
     217 
     218             // already extended
     219             if (typeProto[methodName] == func) continue;
     220 
     221             // already defined(example Array#reverse/join/forEach...)
     222             if (typeProto[methodName] != null) {
     223                 methodName = methodName + "ByLinq";
     224                 if (typeProto[methodName] == func) continue; // recheck
     225             }
     226 
     227             if (func instanceof Function) {
     228                 Utils.defineProperty(typeProto, methodName, func);
     229             }
     230         }
     231     };
     232 
     233     Enumerable.Utils.recallFrom = function (type) {
     234         var typeProto = type.prototype;
     235         var enumerableProto;
     236 
     237         if (type === Array) {
     238             enumerableProto = ArrayEnumerable.prototype;
     239             delete typeProto.getSource;
     240         }
     241         else {
     242             enumerableProto = Enumerable.prototype;
     243             delete typeProto.getEnumerator;
     244         }
     245 
     246         for (var methodName in enumerableProto) {
     247             var func = enumerableProto[methodName];
     248 
     249             if (typeProto[methodName + 'ByLinq']) {
     250                 delete typeProto[methodName + 'ByLinq'];
     251             }
     252             else if (typeProto[methodName] == func && func instanceof Function) {
     253                 delete typeProto[methodName];
     254             }
     255         }
     256     };
     257 
     258     // Generator
     259 
     260     Enumerable.choice = function () // variable argument
     261     {
     262         var args = arguments;
     263 
     264         return new Enumerable(function () {
     265             return new IEnumerator(
     266                 function () {
     267                     args = (args[0] instanceof Array) ? args[0]
     268                         : (args[0].getEnumerator != null) ? args[0].toArray()
     269                         : args;
     270                 },
     271                 function () {
     272                     return this.yieldReturn(args[Math.floor(Math.random() * args.length)]);
     273                 },
     274                 Functions.Blank);
     275         });
     276     };
     277 
     278     Enumerable.cycle = function () // variable argument
     279     {
     280         var args = arguments;
     281 
     282         return new Enumerable(function () {
     283             var index = 0;
     284             return new IEnumerator(
     285                 function () {
     286                     args = (args[0] instanceof Array) ? args[0]
     287                         : (args[0].getEnumerator != null) ? args[0].toArray()
     288                         : args;
     289                 },
     290                 function () {
     291                     if (index >= args.length) index = 0;
     292                     return this.yieldReturn(args[index++]);
     293                 },
     294                 Functions.Blank);
     295         });
     296     };
     297 
     298     Enumerable.empty = function () {
     299         return new Enumerable(function () {
     300             return new IEnumerator(
     301                 Functions.Blank,
     302                 function () { return false; },
     303                 Functions.Blank);
     304         });
     305     };
     306 
     307     Enumerable.from = function (obj) {
     308         if (obj == null) {
     309             return Enumerable.empty();
     310         }
     311         if (obj instanceof Enumerable) {
     312             return obj;
     313         }
     314         if (typeof obj == Types.Number || typeof obj == Types.Boolean) {
     315             return Enumerable.repeat(obj, 1);
     316         }
     317         if (typeof obj == Types.String) {
     318             return new Enumerable(function () {
     319                 var index = 0;
     320                 return new IEnumerator(
     321                     Functions.Blank,
     322                     function () {
     323                         return (index < obj.length) ? this.yieldReturn(obj.charAt(index++)) : false;
     324                     },
     325                     Functions.Blank);
     326             });
     327         }
     328         if (typeof obj != Types.Function) {
     329             // array or array like object
     330             if (typeof obj.length == Types.Number) {
     331                 return new ArrayEnumerable(obj);
     332             }
     333 
     334             // iterable object
     335             if (typeof Symbol !== 'undefined' && typeof obj[Symbol.iterator] !== 'undefined') {
     336                 return new Enumerable(function () {
     337                     return new IEnumerator(
     338                         Functions.Blank,
     339                         function () {
     340                             var next = obj.next();
     341                             return (next.done ? false : (this.yieldReturn(next.value)));
     342                         },
     343                         Functions.Blank);
     344                 });
     345             }
     346 
     347             // JScript's IEnumerable
     348             if (!(obj instanceof Object) && Utils.isIEnumerable(obj)) {
     349                 return new Enumerable(function () {
     350                     var isFirst = true;
     351                     var enumerator;
     352                     return new IEnumerator(
     353                         function () { enumerator = new Enumerator(obj); },
     354                         function () {
     355                             if (isFirst) isFirst = false;
     356                             else enumerator.moveNext();
     357 
     358                             return (enumerator.atEnd()) ? false : this.yieldReturn(enumerator.item());
     359                         },
     360                         Functions.Blank);
     361                 });
     362             }
     363 
     364             // WinMD IIterable<T>
     365             if (typeof Windows === Types.Object && typeof obj.first === Types.Function) {
     366                 return new Enumerable(function () {
     367                     var isFirst = true;
     368                     var enumerator;
     369                     return new IEnumerator(
     370                         function () { enumerator = obj.first(); },
     371                         function () {
     372                             if (isFirst) isFirst = false;
     373                             else enumerator.moveNext();
     374 
     375                             return (enumerator.hasCurrent) ? this.yieldReturn(enumerator.current) : this.yieldBreak();
     376                         },
     377                         Functions.Blank);
     378                 });
     379             }
     380         }
     381 
     382         // case function/object : Create keyValuePair[]
     383         return new Enumerable(function () {
     384             var array = [];
     385             var index = 0;
     386 
     387             return new IEnumerator(
     388                 function () {
     389                     for (var key in obj) {
     390                         var value = obj[key];
     391                         if (!(value instanceof Function) && Object.prototype.hasOwnProperty.call(obj, key)) {
     392                             array.push({ key: key, value: value });
     393                         }
     394                     }
     395                 },
     396                 function () {
     397                     return (index < array.length)
     398                         ? this.yieldReturn(array[index++])
     399                         : false;
     400                 },
     401                 Functions.Blank);
     402         });
     403     },
     404 
     405     Enumerable.make = function (element) {
     406         return Enumerable.repeat(element, 1);
     407     };
     408 
     409     // Overload:function(input, pattern)
     410     // Overload:function(input, pattern, flags)
     411     Enumerable.matches = function (input, pattern, flags) {
     412         if (flags == null) flags = "";
     413         if (pattern instanceof RegExp) {
     414             flags += (pattern.ignoreCase) ? "i" : "";
     415             flags += (pattern.multiline) ? "m" : "";
     416             pattern = pattern.source;
     417         }
     418         if (flags.indexOf("g") === -1) flags += "g";
     419 
     420         return new Enumerable(function () {
     421             var regex;
     422             return new IEnumerator(
     423                 function () { regex = new RegExp(pattern, flags); },
     424                 function () {
     425                     var match = regex.exec(input);
     426                     return (match) ? this.yieldReturn(match) : false;
     427                 },
     428                 Functions.Blank);
     429         });
     430     };
     431 
     432     // Overload:function(start, count)
     433     // Overload:function(start, count, step)
     434     Enumerable.range = function (start, count, step) {
     435         if (step == null) step = 1;
     436 
     437         return new Enumerable(function () {
     438             var value;
     439             var index = 0;
     440 
     441             return new IEnumerator(
     442                 function () { value = start - step; },
     443                 function () {
     444                     return (index++ < count)
     445                         ? this.yieldReturn(value += step)
     446                         : this.yieldBreak();
     447                 },
     448                 Functions.Blank);
     449         });
     450     };
     451 
     452     // Overload:function(start, count)
     453     // Overload:function(start, count, step)
     454     Enumerable.rangeDown = function (start, count, step) {
     455         if (step == null) step = 1;
     456 
     457         return new Enumerable(function () {
     458             var value;
     459             var index = 0;
     460 
     461             return new IEnumerator(
     462                 function () { value = start + step; },
     463                 function () {
     464                     return (index++ < count)
     465                         ? this.yieldReturn(value -= step)
     466                         : this.yieldBreak();
     467                 },
     468                 Functions.Blank);
     469         });
     470     };
     471 
     472     // Overload:function(start, to)
     473     // Overload:function(start, to, step)
     474     Enumerable.rangeTo = function (start, to, step) {
     475         if (step == null) step = 1;
     476 
     477         if (start < to) {
     478             return new Enumerable(function () {
     479                 var value;
     480 
     481                 return new IEnumerator(
     482                 function () { value = start - step; },
     483                 function () {
     484                     var next = value += step;
     485                     return (next <= to)
     486                         ? this.yieldReturn(next)
     487                         : this.yieldBreak();
     488                 },
     489                 Functions.Blank);
     490             });
     491         }
     492         else {
     493             return new Enumerable(function () {
     494                 var value;
     495 
     496                 return new IEnumerator(
     497                 function () { value = start + step; },
     498                 function () {
     499                     var next = value -= step;
     500                     return (next >= to)
     501                         ? this.yieldReturn(next)
     502                         : this.yieldBreak();
     503                 },
     504                 Functions.Blank);
     505             });
     506         }
     507     };
     508 
     509     // Overload:function(element)
     510     // Overload:function(element, count)
     511     Enumerable.repeat = function (element, count) {
     512         if (count != null) return Enumerable.repeat(element).take(count);
     513 
     514         return new Enumerable(function () {
     515             return new IEnumerator(
     516                 Functions.Blank,
     517                 function () { return this.yieldReturn(element); },
     518                 Functions.Blank);
     519         });
     520     };
     521 
     522     Enumerable.repeatWithFinalize = function (initializer, finalizer) {
     523         initializer = Utils.createLambda(initializer);
     524         finalizer = Utils.createLambda(finalizer);
     525 
     526         return new Enumerable(function () {
     527             var element;
     528             return new IEnumerator(
     529                 function () { element = initializer(); },
     530                 function () { return this.yieldReturn(element); },
     531                 function () {
     532                     if (element != null) {
     533                         finalizer(element);
     534                         element = null;
     535                     }
     536                 });
     537         });
     538     };
     539 
     540     // Overload:function(func)
     541     // Overload:function(func, count)
     542     Enumerable.generate = function (func, count) {
     543         if (count != null) return Enumerable.generate(func).take(count);
     544         func = Utils.createLambda(func);
     545 
     546         return new Enumerable(function () {
     547             return new IEnumerator(
     548                 Functions.Blank,
     549                 function () { return this.yieldReturn(func()); },
     550                 Functions.Blank);
     551         });
     552     };
     553 
     554     // Overload:function()
     555     // Overload:function(start)
     556     // Overload:function(start, step)
     557     Enumerable.toInfinity = function (start, step) {
     558         if (start == null) start = 0;
     559         if (step == null) step = 1;
     560 
     561         return new Enumerable(function () {
     562             var value;
     563             return new IEnumerator(
     564                 function () { value = start - step; },
     565                 function () { return this.yieldReturn(value += step); },
     566                 Functions.Blank);
     567         });
     568     };
     569 
     570     // Overload:function()
     571     // Overload:function(start)
     572     // Overload:function(start, step)
     573     Enumerable.toNegativeInfinity = function (start, step) {
     574         if (start == null) start = 0;
     575         if (step == null) step = 1;
     576 
     577         return new Enumerable(function () {
     578             var value;
     579             return new IEnumerator(
     580                 function () { value = start + step; },
     581                 function () { return this.yieldReturn(value -= step); },
     582                 Functions.Blank);
     583         });
     584     };
     585 
     586     Enumerable.unfold = function (seed, func) {
     587         func = Utils.createLambda(func);
     588 
     589         return new Enumerable(function () {
     590             var isFirst = true;
     591             var value;
     592             return new IEnumerator(
     593                 Functions.Blank,
     594                 function () {
     595                     if (isFirst) {
     596                         isFirst = false;
     597                         value = seed;
     598                         return this.yieldReturn(value);
     599                     }
     600                     value = func(value);
     601                     return this.yieldReturn(value);
     602                 },
     603                 Functions.Blank);
     604         });
     605     };
     606 
     607     Enumerable.defer = function (enumerableFactory) {
     608 
     609         return new Enumerable(function () {
     610             var enumerator;
     611 
     612             return new IEnumerator(
     613                 function () { enumerator = Enumerable.from(enumerableFactory()).getEnumerator(); },
     614                 function () {
     615                     return (enumerator.moveNext())
     616                         ? this.yieldReturn(enumerator.current())
     617                         : this.yieldBreak();
     618                 },
     619                 function () {
     620                     Utils.dispose(enumerator);
     621                 });
     622         });
     623     };
     624 
     625     // Extension Methods
     626 
     627     /* Projection and Filtering Methods */
     628 
     629     // Overload:function(func)
     630     // Overload:function(func, resultSelector<element>)
     631     // Overload:function(func, resultSelector<element, nestLevel>)
     632     Enumerable.prototype.traverseBreadthFirst = function (func, resultSelector) {
     633         var source = this;
     634         func = Utils.createLambda(func);
     635         resultSelector = Utils.createLambda(resultSelector);
     636 
     637         return new Enumerable(function () {
     638             var enumerator;
     639             var nestLevel = 0;
     640             var buffer = [];
     641 
     642             return new IEnumerator(
     643                 function () { enumerator = source.getEnumerator(); },
     644                 function () {
     645                     while (true) {
     646                         if (enumerator.moveNext()) {
     647                             buffer.push(enumerator.current());
     648                             return this.yieldReturn(resultSelector(enumerator.current(), nestLevel));
     649                         }
     650 
     651                         var next = Enumerable.from(buffer).selectMany(function (x) { return func(x); });
     652                         if (!next.any()) {
     653                             return false;
     654                         }
     655                         else {
     656                             nestLevel++;
     657                             buffer = [];
     658                             Utils.dispose(enumerator);
     659                             enumerator = next.getEnumerator();
     660                         }
     661                     }
     662                 },
     663                 function () { Utils.dispose(enumerator); });
     664         });
     665     };
     666 
     667     // Overload:function(func)
     668     // Overload:function(func, resultSelector<element>)
     669     // Overload:function(func, resultSelector<element, nestLevel>)
     670     Enumerable.prototype.traverseDepthFirst = function (func, resultSelector) {
     671         var source = this;
     672         func = Utils.createLambda(func);
     673         resultSelector = Utils.createLambda(resultSelector);
     674 
     675         return new Enumerable(function () {
     676             var enumeratorStack = [];
     677             var enumerator;
     678 
     679             return new IEnumerator(
     680                 function () { enumerator = source.getEnumerator(); },
     681                 function () {
     682                     while (true) {
     683                         if (enumerator.moveNext()) {
     684                             var value = resultSelector(enumerator.current(), enumeratorStack.length);
     685                             enumeratorStack.push(enumerator);
     686                             enumerator = Enumerable.from(func(enumerator.current())).getEnumerator();
     687                             return this.yieldReturn(value);
     688                         }
     689 
     690                         if (enumeratorStack.length <= 0) return false;
     691                         Utils.dispose(enumerator);
     692                         enumerator = enumeratorStack.pop();
     693                     }
     694                 },
     695                 function () {
     696                     try {
     697                         Utils.dispose(enumerator);
     698                     }
     699                     finally {
     700                         Enumerable.from(enumeratorStack).forEach(function (s) { s.dispose(); });
     701                     }
     702                 });
     703         });
     704     };
     705 
     706     Enumerable.prototype.flatten = function () {
     707         var source = this;
     708 
     709         return new Enumerable(function () {
     710             var enumerator;
     711             var middleEnumerator = null;
     712 
     713             return new IEnumerator(
     714                 function () { enumerator = source.getEnumerator(); },
     715                 function () {
     716                     while (true) {
     717                         if (middleEnumerator != null) {
     718                             if (middleEnumerator.moveNext()) {
     719                                 return this.yieldReturn(middleEnumerator.current());
     720                             }
     721                             else {
     722                                 middleEnumerator = null;
     723                             }
     724                         }
     725 
     726                         if (enumerator.moveNext()) {
     727                             if (enumerator.current() instanceof Array) {
     728                                 Utils.dispose(middleEnumerator);
     729                                 middleEnumerator = Enumerable.from(enumerator.current())
     730                                     .selectMany(Functions.Identity)
     731                                     .flatten()
     732                                     .getEnumerator();
     733                                 continue;
     734                             }
     735                             else {
     736                                 return this.yieldReturn(enumerator.current());
     737                             }
     738                         }
     739 
     740                         return false;
     741                     }
     742                 },
     743                 function () {
     744                     try {
     745                         Utils.dispose(enumerator);
     746                     }
     747                     finally {
     748                         Utils.dispose(middleEnumerator);
     749                     }
     750                 });
     751         });
     752     };
     753 
     754     Enumerable.prototype.pairwise = function (selector) {
     755         var source = this;
     756         selector = Utils.createLambda(selector);
     757 
     758         return new Enumerable(function () {
     759             var enumerator;
     760 
     761             return new IEnumerator(
     762                 function () {
     763                     enumerator = source.getEnumerator();
     764                     enumerator.moveNext();
     765                 },
     766                 function () {
     767                     var prev = enumerator.current();
     768                     return (enumerator.moveNext())
     769                         ? this.yieldReturn(selector(prev, enumerator.current()))
     770                         : false;
     771                 },
     772                 function () { Utils.dispose(enumerator); });
     773         });
     774     };
     775 
     776     // Overload:function(func)
     777     // Overload:function(seed,func<value,element>)
     778     Enumerable.prototype.scan = function (seed, func) {
     779         var isUseSeed;
     780         if (func == null) {
     781             func = Utils.createLambda(seed); // arguments[0]
     782             isUseSeed = false;
     783         } else {
     784             func = Utils.createLambda(func);
     785             isUseSeed = true;
     786         }
     787         var source = this;
     788 
     789         return new Enumerable(function () {
     790             var enumerator;
     791             var value;
     792             var isFirst = true;
     793 
     794             return new IEnumerator(
     795                 function () { enumerator = source.getEnumerator(); },
     796                 function () {
     797                     if (isFirst) {
     798                         isFirst = false;
     799                         if (!isUseSeed) {
     800                             if (enumerator.moveNext()) {
     801                                 return this.yieldReturn(value = enumerator.current());
     802                             }
     803                         }
     804                         else {
     805                             return this.yieldReturn(value = seed);
     806                         }
     807                     }
     808 
     809                     return (enumerator.moveNext())
     810                         ? this.yieldReturn(value = func(value, enumerator.current()))
     811                         : false;
     812                 },
     813                 function () { Utils.dispose(enumerator); });
     814         });
     815     };
     816 
     817     // Overload:function(selector<element>)
     818     // Overload:function(selector<element,index>)
     819     Enumerable.prototype.select = function (selector) {
     820         selector = Utils.createLambda(selector);
     821 
     822         if (selector.length <= 1) {
     823             return new WhereSelectEnumerable(this, null, selector);
     824         }
     825         else {
     826             var source = this;
     827 
     828             return new Enumerable(function () {
     829                 var enumerator;
     830                 var index = 0;
     831 
     832                 return new IEnumerator(
     833                     function () { enumerator = source.getEnumerator(); },
     834                     function () {
     835                         return (enumerator.moveNext())
     836                             ? this.yieldReturn(selector(enumerator.current(), index++))
     837                             : false;
     838                     },
     839                     function () { Utils.dispose(enumerator); });
     840             });
     841         }
     842     };
     843 
     844     // Overload:function(collectionSelector<element>)
     845     // Overload:function(collectionSelector<element,index>)
     846     // Overload:function(collectionSelector<element>,resultSelector)
     847     // Overload:function(collectionSelector<element,index>,resultSelector)
     848     Enumerable.prototype.selectMany = function (collectionSelector, resultSelector) {
     849         var source = this;
     850         collectionSelector = Utils.createLambda(collectionSelector);
     851         if (resultSelector == null) resultSelector = function (a, b) { return b; };
     852         resultSelector = Utils.createLambda(resultSelector);
     853 
     854         return new Enumerable(function () {
     855             var enumerator;
     856             var middleEnumerator = undefined;
     857             var index = 0;
     858 
     859             return new IEnumerator(
     860                 function () { enumerator = source.getEnumerator(); },
     861                 function () {
     862                     if (middleEnumerator === undefined) {
     863                         if (!enumerator.moveNext()) return false;
     864                     }
     865                     do {
     866                         if (middleEnumerator == null) {
     867                             var middleSeq = collectionSelector(enumerator.current(), index++);
     868                             middleEnumerator = Enumerable.from(middleSeq).getEnumerator();
     869                         }
     870                         if (middleEnumerator.moveNext()) {
     871                             return this.yieldReturn(resultSelector(enumerator.current(), middleEnumerator.current()));
     872                         }
     873                         Utils.dispose(middleEnumerator);
     874                         middleEnumerator = null;
     875                     } while (enumerator.moveNext());
     876                     return false;
     877                 },
     878                 function () {
     879                     try {
     880                         Utils.dispose(enumerator);
     881                     }
     882                     finally {
     883                         Utils.dispose(middleEnumerator);
     884                     }
     885                 });
     886         });
     887     };
     888 
     889     // Overload:function(predicate<element>)
     890     // Overload:function(predicate<element,index>)
     891     Enumerable.prototype.where = function (predicate) {
     892         predicate = Utils.createLambda(predicate);
     893 
     894         if (predicate.length <= 1) {
     895             return new WhereEnumerable(this, predicate);
     896         }
     897         else {
     898             var source = this;
     899 
     900             return new Enumerable(function () {
     901                 var enumerator;
     902                 var index = 0;
     903 
     904                 return new IEnumerator(
     905                     function () { enumerator = source.getEnumerator(); },
     906                     function () {
     907                         while (enumerator.moveNext()) {
     908                             if (predicate(enumerator.current(), index++)) {
     909                                 return this.yieldReturn(enumerator.current());
     910                             }
     911                         }
     912                         return false;
     913                     },
     914                     function () { Utils.dispose(enumerator); });
     915             });
     916         }
     917     };
     918 
     919 
     920     // Overload:function(selector<element>)
     921     // Overload:function(selector<element,index>)
     922     Enumerable.prototype.choose = function (selector) {
     923         selector = Utils.createLambda(selector);
     924         var source = this;
     925 
     926         return new Enumerable(function () {
     927             var enumerator;
     928             var index = 0;
     929 
     930             return new IEnumerator(
     931                 function () { enumerator = source.getEnumerator(); },
     932                 function () {
     933                     while (enumerator.moveNext()) {
     934                         var result = selector(enumerator.current(), index++);
     935                         if (result != null) {
     936                             return this.yieldReturn(result);
     937                         }
     938                     }
     939                     return this.yieldBreak();
     940                 },
     941                 function () { Utils.dispose(enumerator); });
     942         });
     943     };
     944 
     945     Enumerable.prototype.ofType = function (type) {
     946         var typeName;
     947         switch (type) {
     948             case Number:
     949                 typeName = Types.Number;
     950                 break;
     951             case String:
     952                 typeName = Types.String;
     953                 break;
     954             case Boolean:
     955                 typeName = Types.Boolean;
     956                 break;
     957             case Function:
     958                 typeName = Types.Function;
     959                 break;
     960             default:
     961                 typeName = null;
     962                 break;
     963         }
     964         return (typeName === null)
     965             ? this.where(function (x) { return x instanceof type; })
     966             : this.where(function (x) { return typeof x === typeName; });
     967     };
     968 
     969     // mutiple arguments, last one is selector, others are enumerable
     970     Enumerable.prototype.zip = function () {
     971         var args = arguments;
     972         var selector = Utils.createLambda(arguments[arguments.length - 1]);
     973 
     974         var source = this;
     975         // optimized case:argument is 2
     976         if (arguments.length == 2) {
     977             var second = arguments[0];
     978 
     979             return new Enumerable(function () {
     980                 var firstEnumerator;
     981                 var secondEnumerator;
     982                 var index = 0;
     983 
     984                 return new IEnumerator(
     985                 function () {
     986                     firstEnumerator = source.getEnumerator();
     987                     secondEnumerator = Enumerable.from(second).getEnumerator();
     988                 },
     989                 function () {
     990                     if (firstEnumerator.moveNext() && secondEnumerator.moveNext()) {
     991                         return this.yieldReturn(selector(firstEnumerator.current(), secondEnumerator.current(), index++));
     992                     }
     993                     return false;
     994                 },
     995                 function () {
     996                     try {
     997                         Utils.dispose(firstEnumerator);
     998                     } finally {
     999                         Utils.dispose(secondEnumerator);
    1000                     }
    1001                 });
    1002             });
    1003         }
    1004         else {
    1005             return new Enumerable(function () {
    1006                 var enumerators;
    1007                 var index = 0;
    1008 
    1009                 return new IEnumerator(
    1010                 function () {
    1011                     var array = Enumerable.make(source)
    1012                         .concat(Enumerable.from(args).takeExceptLast().select(Enumerable.from))
    1013                         .select(function (x) { return x.getEnumerator() })
    1014                         .toArray();
    1015                     enumerators = Enumerable.from(array);
    1016                 },
    1017                 function () {
    1018                     if (enumerators.all(function (x) { return x.moveNext() })) {
    1019                         var array = enumerators
    1020                             .select(function (x) { return x.current() })
    1021                             .toArray();
    1022                         array.push(index++);
    1023                         return this.yieldReturn(selector.apply(null, array));
    1024                     }
    1025                     else {
    1026                         return this.yieldBreak();
    1027                     }
    1028                 },
    1029                 function () {
    1030                     Enumerable.from(enumerators).forEach(Utils.dispose);
    1031                 });
    1032             });
    1033         }
    1034     };
    1035 
    1036     // mutiple arguments
    1037     Enumerable.prototype.merge = function () {
    1038         var args = arguments;
    1039         var source = this;
    1040 
    1041         return new Enumerable(function () {
    1042             var enumerators;
    1043             var index = -1;
    1044 
    1045             return new IEnumerator(
    1046                 function () {
    1047                     enumerators = Enumerable.make(source)
    1048                         .concat(Enumerable.from(args).select(Enumerable.from))
    1049                         .select(function (x) { return x.getEnumerator() })
    1050                         .toArray();
    1051                 },
    1052                 function () {
    1053                     while (enumerators.length > 0) {
    1054                         index = (index >= enumerators.length - 1) ? 0 : index + 1;
    1055                         var enumerator = enumerators[index];
    1056 
    1057                         if (enumerator.moveNext()) {
    1058                             return this.yieldReturn(enumerator.current());
    1059                         }
    1060                         else {
    1061                             enumerator.dispose();
    1062                             enumerators.splice(index--, 1);
    1063                         }
    1064                     }
    1065                     return this.yieldBreak();
    1066                 },
    1067                 function () {
    1068                     Enumerable.from(enumerators).forEach(Utils.dispose);
    1069                 });
    1070         });
    1071     };
    1072 
    1073     /* Join Methods */
    1074 
    1075     // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
    1076     // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
    1077     Enumerable.prototype.join = function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector) {
    1078         outerKeySelector = Utils.createLambda(outerKeySelector);
    1079         innerKeySelector = Utils.createLambda(innerKeySelector);
    1080         resultSelector = Utils.createLambda(resultSelector);
    1081         compareSelector = Utils.createLambda(compareSelector);
    1082         var source = this;
    1083 
    1084         return new Enumerable(function () {
    1085             var outerEnumerator;
    1086             var lookup;
    1087             var innerElements = null;
    1088             var innerCount = 0;
    1089 
    1090             return new IEnumerator(
    1091                 function () {
    1092                     outerEnumerator = source.getEnumerator();
    1093                     lookup = Enumerable.from(inner).toLookup(innerKeySelector, Functions.Identity, compareSelector);
    1094                 },
    1095                 function () {
    1096                     while (true) {
    1097                         if (innerElements != null) {
    1098                             var innerElement = innerElements[innerCount++];
    1099                             if (innerElement !== undefined) {
    1100                                 return this.yieldReturn(resultSelector(outerEnumerator.current(), innerElement));
    1101                             }
    1102 
    1103                             innerElement = null;
    1104                             innerCount = 0;
    1105                         }
    1106 
    1107                         if (outerEnumerator.moveNext()) {
    1108                             var key = outerKeySelector(outerEnumerator.current());
    1109                             innerElements = lookup.get(key).toArray();
    1110                         } else {
    1111                             return false;
    1112                         }
    1113                     }
    1114                 },
    1115                 function () { Utils.dispose(outerEnumerator); });
    1116         });
    1117     };
    1118 
    1119     // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
    1120     // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
    1121     Enumerable.prototype.groupJoin = function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector) {
    1122         outerKeySelector = Utils.createLambda(outerKeySelector);
    1123         innerKeySelector = Utils.createLambda(innerKeySelector);
    1124         resultSelector = Utils.createLambda(resultSelector);
    1125         compareSelector = Utils.createLambda(compareSelector);
    1126         var source = this;
    1127 
    1128         return new Enumerable(function () {
    1129             var enumerator = source.getEnumerator();
    1130             var lookup = null;
    1131 
    1132             return new IEnumerator(
    1133                 function () {
    1134                     enumerator = source.getEnumerator();
    1135                     lookup = Enumerable.from(inner).toLookup(innerKeySelector, Functions.Identity, compareSelector);
    1136                 },
    1137                 function () {
    1138                     if (enumerator.moveNext()) {
    1139                         var innerElement = lookup.get(outerKeySelector(enumerator.current()));
    1140                         return this.yieldReturn(resultSelector(enumerator.current(), innerElement));
    1141                     }
    1142                     return false;
    1143                 },
    1144                 function () { Utils.dispose(enumerator); });
    1145         });
    1146     };
    1147 
    1148     /* Set Methods */
    1149 
    1150     Enumerable.prototype.all = function (predicate) {
    1151         predicate = Utils.createLambda(predicate);
    1152 
    1153         var result = true;
    1154         this.forEach(function (x) {
    1155             if (!predicate(x)) {
    1156                 result = false;
    1157                 return false; // break
    1158             }
    1159         });
    1160         return result;
    1161     };
    1162 
    1163     // Overload:function()
    1164     // Overload:function(predicate)
    1165     Enumerable.prototype.any = function (predicate) {
    1166         predicate = Utils.createLambda(predicate);
    1167 
    1168         var enumerator = this.getEnumerator();
    1169         try {
    1170             if (arguments.length == 0) return enumerator.moveNext(); // case:function()
    1171 
    1172             while (enumerator.moveNext()) // case:function(predicate)
    1173             {
    1174                 if (predicate(enumerator.current())) return true;
    1175             }
    1176             return false;
    1177         }
    1178         finally {
    1179             Utils.dispose(enumerator);
    1180         }
    1181     };
    1182 
    1183     Enumerable.prototype.isEmpty = function () {
    1184         return !this.any();
    1185     };
    1186 
    1187     // multiple arguments
    1188     Enumerable.prototype.concat = function () {
    1189         var source = this;
    1190 
    1191         if (arguments.length == 1) {
    1192             var second = arguments[0];
    1193 
    1194             return new Enumerable(function () {
    1195                 var firstEnumerator;
    1196                 var secondEnumerator;
    1197 
    1198                 return new IEnumerator(
    1199                 function () { firstEnumerator = source.getEnumerator(); },
    1200                 function () {
    1201                     if (secondEnumerator == null) {
    1202                         if (firstEnumerator.moveNext()) return this.yieldReturn(firstEnumerator.current());
    1203                         secondEnumerator = Enumerable.from(second).getEnumerator();
    1204                     }
    1205                     if (secondEnumerator.moveNext()) return this.yieldReturn(secondEnumerator.current());
    1206                     return false;
    1207                 },
    1208                 function () {
    1209                     try {
    1210                         Utils.dispose(firstEnumerator);
    1211                     }
    1212                     finally {
    1213                         Utils.dispose(secondEnumerator);
    1214                     }
    1215                 });
    1216             });
    1217         }
    1218         else {
    1219             var args = arguments;
    1220 
    1221             return new Enumerable(function () {
    1222                 var enumerators;
    1223 
    1224                 return new IEnumerator(
    1225                     function () {
    1226                         enumerators = Enumerable.make(source)
    1227                             .concat(Enumerable.from(args).select(Enumerable.from))
    1228                             .select(function (x) { return x.getEnumerator() })
    1229                             .toArray();
    1230                     },
    1231                     function () {
    1232                         while (enumerators.length > 0) {
    1233                             var enumerator = enumerators[0];
    1234 
    1235                             if (enumerator.moveNext()) {
    1236                                 return this.yieldReturn(enumerator.current());
    1237                             }
    1238                             else {
    1239                                 enumerator.dispose();
    1240                                 enumerators.splice(0, 1);
    1241                             }
    1242                         }
    1243                         return this.yieldBreak();
    1244                     },
    1245                     function () {
    1246                         Enumerable.from(enumerators).forEach(Utils.dispose);
    1247                     });
    1248             });
    1249         }
    1250     };
    1251 
    1252     Enumerable.prototype.insert = function (index, second) {
    1253         var source = this;
    1254 
    1255         return new Enumerable(function () {
    1256             var firstEnumerator;
    1257             var secondEnumerator;
    1258             var count = 0;
    1259             var isEnumerated = false;
    1260 
    1261             return new IEnumerator(
    1262                 function () {
    1263                     firstEnumerator = source.getEnumerator();
    1264                     secondEnumerator = Enumerable.from(second).getEnumerator();
    1265                 },
    1266                 function () {
    1267                     if (count == index && secondEnumerator.moveNext()) {
    1268                         isEnumerated = true;
    1269                         return this.yieldReturn(secondEnumerator.current());
    1270                     }
    1271                     if (firstEnumerator.moveNext()) {
    1272                         count++;
    1273                         return this.yieldReturn(firstEnumerator.current());
    1274                     }
    1275                     if (!isEnumerated && secondEnumerator.moveNext()) {
    1276                         return this.yieldReturn(secondEnumerator.current());
    1277                     }
    1278                     return false;
    1279                 },
    1280                 function () {
    1281                     try {
    1282                         Utils.dispose(firstEnumerator);
    1283                     }
    1284                     finally {
    1285                         Utils.dispose(secondEnumerator);
    1286                     }
    1287                 });
    1288         });
    1289     };
    1290 
    1291     Enumerable.prototype.alternate = function (alternateValueOrSequence) {
    1292         var source = this;
    1293 
    1294         return new Enumerable(function () {
    1295             var buffer;
    1296             var enumerator;
    1297             var alternateSequence;
    1298             var alternateEnumerator;
    1299 
    1300             return new IEnumerator(
    1301                 function () {
    1302                     if (alternateValueOrSequence instanceof Array || alternateValueOrSequence.getEnumerator != null) {
    1303                         alternateSequence = Enumerable.from(Enumerable.from(alternateValueOrSequence).toArray()); // freeze
    1304                     }
    1305                     else {
    1306                         alternateSequence = Enumerable.make(alternateValueOrSequence);
    1307                     }
    1308                     enumerator = source.getEnumerator();
    1309                     if (enumerator.moveNext()) buffer = enumerator.current();
    1310                 },
    1311                 function () {
    1312                     while (true) {
    1313                         if (alternateEnumerator != null) {
    1314                             if (alternateEnumerator.moveNext()) {
    1315                                 return this.yieldReturn(alternateEnumerator.current());
    1316                             }
    1317                             else {
    1318                                 alternateEnumerator = null;
    1319                             }
    1320                         }
    1321 
    1322                         if (buffer == null && enumerator.moveNext()) {
    1323                             buffer = enumerator.current(); // hasNext
    1324                             alternateEnumerator = alternateSequence.getEnumerator();
    1325                             continue; // GOTO
    1326                         }
    1327                         else if (buffer != null) {
    1328                             var retVal = buffer;
    1329                             buffer = null;
    1330                             return this.yieldReturn(retVal);
    1331                         }
    1332 
    1333                         return this.yieldBreak();
    1334                     }
    1335                 },
    1336                 function () {
    1337                     try {
    1338                         Utils.dispose(enumerator);
    1339                     }
    1340                     finally {
    1341                         Utils.dispose(alternateEnumerator);
    1342                     }
    1343                 });
    1344         });
    1345     };
    1346 
    1347     // Overload:function(value)
    1348     // Overload:function(value, compareSelector)
    1349     Enumerable.prototype.contains = function (value, compareSelector) {
    1350         compareSelector = Utils.createLambda(compareSelector);
    1351         var enumerator = this.getEnumerator();
    1352         try {
    1353             while (enumerator.moveNext()) {
    1354                 if (compareSelector(enumerator.current()) === value) return true;
    1355             }
    1356             return false;
    1357         }
    1358         finally {
    1359             Utils.dispose(enumerator);
    1360         }
    1361     };
    1362 
    1363     Enumerable.prototype.defaultIfEmpty = function (defaultValue) {
    1364         var source = this;
    1365         if (defaultValue === undefined) defaultValue = null;
    1366 
    1367         return new Enumerable(function () {
    1368             var enumerator;
    1369             var isFirst = true;
    1370 
    1371             return new IEnumerator(
    1372                 function () { enumerator = source.getEnumerator(); },
    1373                 function () {
    1374                     if (enumerator.moveNext()) {
    1375                         isFirst = false;
    1376                         return this.yieldReturn(enumerator.current());
    1377                     }
    1378                     else if (isFirst) {
    1379                         isFirst = false;
    1380                         return this.yieldReturn(defaultValue);
    1381                     }
    1382                     return false;
    1383                 },
    1384                 function () { Utils.dispose(enumerator); });
    1385         });
    1386     };
    1387 
    1388     // Overload:function()
    1389     // Overload:function(compareSelector)
    1390     Enumerable.prototype.distinct = function (compareSelector) {
    1391         return this.except(Enumerable.empty(), compareSelector);
    1392     };
    1393 
    1394     Enumerable.prototype.distinctUntilChanged = function (compareSelector) {
    1395         compareSelector = Utils.createLambda(compareSelector);
    1396         var source = this;
    1397 
    1398         return new Enumerable(function () {
    1399             var enumerator;
    1400             var compareKey;
    1401             var initial;
    1402 
    1403             return new IEnumerator(
    1404                 function () {
    1405                     enumerator = source.getEnumerator();
    1406                 },
    1407                 function () {
    1408                     while (enumerator.moveNext()) {
    1409                         var key = compareSelector(enumerator.current());
    1410 
    1411                         if (initial) {
    1412                             initial = false;
    1413                             compareKey = key;
    1414                             return this.yieldReturn(enumerator.current());
    1415                         }
    1416 
    1417                         if (compareKey === key) {
    1418                             continue;
    1419                         }
    1420 
    1421                         compareKey = key;
    1422                         return this.yieldReturn(enumerator.current());
    1423                     }
    1424                     return this.yieldBreak();
    1425                 },
    1426                 function () { Utils.dispose(enumerator); });
    1427         });
    1428     };
    1429 
    1430     // Overload:function(second)
    1431     // Overload:function(second, compareSelector)
    1432     Enumerable.prototype.except = function (second, compareSelector) {
    1433         compareSelector = Utils.createLambda(compareSelector);
    1434         var source = this;
    1435 
    1436         return new Enumerable(function () {
    1437             var enumerator;
    1438             var keys;
    1439 
    1440             return new IEnumerator(
    1441                 function () {
    1442                     enumerator = source.getEnumerator();
    1443                     keys = new Dictionary(compareSelector);
    1444                     Enumerable.from(second).forEach(function (key) { keys.add(key); });
    1445                 },
    1446                 function () {
    1447                     while (enumerator.moveNext()) {
    1448                         var current = enumerator.current();
    1449                         if (!keys.contains(current)) {
    1450                             keys.add(current);
    1451                             return this.yieldReturn(current);
    1452                         }
    1453                     }
    1454                     return false;
    1455                 },
    1456                 function () { Utils.dispose(enumerator); });
    1457         });
    1458     };
    1459 
    1460     // Overload:function(second)
    1461     // Overload:function(second, compareSelector)
    1462     Enumerable.prototype.intersect = function (second, compareSelector) {
    1463         compareSelector = Utils.createLambda(compareSelector);
    1464         var source = this;
    1465 
    1466         return new Enumerable(function () {
    1467             var enumerator;
    1468             var keys;
    1469             var outs;
    1470 
    1471             return new IEnumerator(
    1472                 function () {
    1473                     enumerator = source.getEnumerator();
    1474 
    1475                     keys = new Dictionary(compareSelector);
    1476                     Enumerable.from(second).forEach(function (key) { keys.add(key); });
    1477                     outs = new Dictionary(compareSelector);
    1478                 },
    1479                 function () {
    1480                     while (enumerator.moveNext()) {
    1481                         var current = enumerator.current();
    1482                         if (!outs.contains(current) && keys.contains(current)) {
    1483                             outs.add(current);
    1484                             return this.yieldReturn(current);
    1485                         }
    1486                     }
    1487                     return false;
    1488                 },
    1489                 function () { Utils.dispose(enumerator); });
    1490         });
    1491     };
    1492 
    1493     // Overload:function(second)
    1494     // Overload:function(second, compareSelector)
    1495     Enumerable.prototype.sequenceEqual = function (second, compareSelector) {
    1496         compareSelector = Utils.createLambda(compareSelector);
    1497 
    1498         var firstEnumerator = this.getEnumerator();
    1499         try {
    1500             var secondEnumerator = Enumerable.from(second).getEnumerator();
    1501             try {
    1502                 while (firstEnumerator.moveNext()) {
    1503                     if (!secondEnumerator.moveNext()
    1504                     || compareSelector(firstEnumerator.current()) !== compareSelector(secondEnumerator.current())) {
    1505                         return false;
    1506                     }
    1507                 }
    1508 
    1509                 if (secondEnumerator.moveNext()) return false;
    1510                 return true;
    1511             }
    1512             finally {
    1513                 Utils.dispose(secondEnumerator);
    1514             }
    1515         }
    1516         finally {
    1517             Utils.dispose(firstEnumerator);
    1518         }
    1519     };
    1520 
    1521     Enumerable.prototype.union = function (second, compareSelector) {
    1522         compareSelector = Utils.createLambda(compareSelector);
    1523         var source = this;
    1524 
    1525         return new Enumerable(function () {
    1526             var firstEnumerator;
    1527             var secondEnumerator;
    1528             var keys;
    1529 
    1530             return new IEnumerator(
    1531                 function () {
    1532                     firstEnumerator = source.getEnumerator();
    1533                     keys = new Dictionary(compareSelector);
    1534                 },
    1535                 function () {
    1536                     var current;
    1537                     if (secondEnumerator === undefined) {
    1538                         while (firstEnumerator.moveNext()) {
    1539                             current = firstEnumerator.current();
    1540                             if (!keys.contains(current)) {
    1541                                 keys.add(current);
    1542                                 return this.yieldReturn(current);
    1543                             }
    1544                         }
    1545                         secondEnumerator = Enumerable.from(second).getEnumerator();
    1546                     }
    1547                     while (secondEnumerator.moveNext()) {
    1548                         current = secondEnumerator.current();
    1549                         if (!keys.contains(current)) {
    1550                             keys.add(current);
    1551                             return this.yieldReturn(current);
    1552                         }
    1553                     }
    1554                     return false;
    1555                 },
    1556                 function () {
    1557                     try {
    1558                         Utils.dispose(firstEnumerator);
    1559                     }
    1560                     finally {
    1561                         Utils.dispose(secondEnumerator);
    1562                     }
    1563                 });
    1564         });
    1565     };
    1566 
    1567     /* Ordering Methods */
    1568 
    1569     Enumerable.prototype.orderBy = function (keySelector, comparer) {
    1570         return new OrderedEnumerable(this, keySelector, comparer, false);
    1571     };
    1572 
    1573     Enumerable.prototype.orderByDescending = function (keySelector, comparer) {
    1574         return new OrderedEnumerable(this, keySelector, comparer, true);
    1575     };
    1576 
    1577     Enumerable.prototype.reverse = function () {
    1578         var source = this;
    1579 
    1580         return new Enumerable(function () {
    1581             var buffer;
    1582             var index;
    1583 
    1584             return new IEnumerator(
    1585                 function () {
    1586                     buffer = source.toArray();
    1587                     index = buffer.length;
    1588                 },
    1589                 function () {
    1590                     return (index > 0)
    1591                         ? this.yieldReturn(buffer[--index])
    1592                         : false;
    1593                 },
    1594                 Functions.Blank);
    1595         });
    1596     };
    1597 
    1598     Enumerable.prototype.shuffle = function () {
    1599         var source = this;
    1600 
    1601         return new Enumerable(function () {
    1602             var buffer;
    1603 
    1604             return new IEnumerator(
    1605                 function () { buffer = source.toArray(); },
    1606                 function () {
    1607                     if (buffer.length > 0) {
    1608                         var i = Math.floor(Math.random() * buffer.length);
    1609                         return this.yieldReturn(buffer.splice(i, 1)[0]);
    1610                     }
    1611                     return false;
    1612                 },
    1613                 Functions.Blank);
    1614         });
    1615     };
    1616 
    1617     Enumerable.prototype.weightedSample = function (weightSelector) {
    1618         weightSelector = Utils.createLambda(weightSelector);
    1619         var source = this;
    1620 
    1621         return new Enumerable(function () {
    1622             var sortedByBound;
    1623             var totalWeight = 0;
    1624 
    1625             return new IEnumerator(
    1626                 function () {
    1627                     sortedByBound = source
    1628                         .choose(function (x) {
    1629                             var weight = weightSelector(x);
    1630                             if (weight <= 0) return null; // ignore 0
    1631 
    1632                             totalWeight += weight;
    1633                             return { value: x, bound: totalWeight };
    1634                         })
    1635                         .toArray();
    1636                 },
    1637                 function () {
    1638                     if (sortedByBound.length > 0) {
    1639                         var draw = Math.floor(Math.random() * totalWeight) + 1;
    1640 
    1641                         var lower = -1;
    1642                         var upper = sortedByBound.length;
    1643                         while (upper - lower > 1) {
    1644                             var index = Math.floor((lower + upper) / 2);
    1645                             if (sortedByBound[index].bound >= draw) {
    1646                                 upper = index;
    1647                             }
    1648                             else {
    1649                                 lower = index;
    1650                             }
    1651                         }
    1652 
    1653                         return this.yieldReturn(sortedByBound[upper].value);
    1654                     }
    1655 
    1656                     return this.yieldBreak();
    1657                 },
    1658                 Functions.Blank);
    1659         });
    1660     };
    1661 
    1662     /* Grouping Methods */
    1663 
    1664     // Overload:function(keySelector)
    1665     // Overload:function(keySelector,elementSelector)
    1666     // Overload:function(keySelector,elementSelector,resultSelector)
    1667     // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
    1668     Enumerable.prototype.groupBy = function (keySelector, elementSelector, resultSelector, compareSelector) {
    1669         var source = this;
    1670         keySelector = Utils.createLambda(keySelector);
    1671         elementSelector = Utils.createLambda(elementSelector);
    1672         if (resultSelector != null) resultSelector = Utils.createLambda(resultSelector);
    1673         compareSelector = Utils.createLambda(compareSelector);
    1674 
    1675         return new Enumerable(function () {
    1676             var enumerator;
    1677 
    1678             return new IEnumerator(
    1679                 function () {
    1680                     enumerator = source.toLookup(keySelector, elementSelector, compareSelector)
    1681                         .toEnumerable()
    1682                         .getEnumerator();
    1683                 },
    1684                 function () {
    1685                     while (enumerator.moveNext()) {
    1686                         return (resultSelector == null)
    1687                             ? this.yieldReturn(enumerator.current())
    1688                             : this.yieldReturn(resultSelector(enumerator.current().key(), enumerator.current()));
    1689                     }
    1690                     return false;
    1691                 },
    1692                 function () { Utils.dispose(enumerator); });
    1693         });
    1694     };
    1695 
    1696     // Overload:function(keySelector)
    1697     // Overload:function(keySelector,elementSelector)
    1698     // Overload:function(keySelector,elementSelector,resultSelector)
    1699     // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
    1700     Enumerable.prototype.partitionBy = function (keySelector, elementSelector, resultSelector, compareSelector) {
    1701 
    1702         var source = this;
    1703         keySelector = Utils.createLambda(keySelector);
    1704         elementSelector = Utils.createLambda(elementSelector);
    1705         compareSelector = Utils.createLambda(compareSelector);
    1706         var hasResultSelector;
    1707         if (resultSelector == null) {
    1708             hasResultSelector = false;
    1709             resultSelector = function (key, group) { return new Grouping(key, group); };
    1710         }
    1711         else {
    1712             hasResultSelector = true;
    1713             resultSelector = Utils.createLambda(resultSelector);
    1714         }
    1715 
    1716         return new Enumerable(function () {
    1717             var enumerator;
    1718             var key;
    1719             var compareKey;
    1720             var group = [];
    1721 
    1722             return new IEnumerator(
    1723                 function () {
    1724                     enumerator = source.getEnumerator();
    1725                     if (enumerator.moveNext()) {
    1726                         key = keySelector(enumerator.current());
    1727                         compareKey = compareSelector(key);
    1728                         group.push(elementSelector(enumerator.current()));
    1729                     }
    1730                 },
    1731                 function () {
    1732                     var hasNext;
    1733                     while ((hasNext = enumerator.moveNext()) == true) {
    1734                         if (compareKey === compareSelector(keySelector(enumerator.current()))) {
    1735                             group.push(elementSelector(enumerator.current()));
    1736                         }
    1737                         else break;
    1738                     }
    1739 
    1740                     if (group.length > 0) {
    1741                         var result = (hasResultSelector)
    1742                             ? resultSelector(key, Enumerable.from(group))
    1743                             : resultSelector(key, group);
    1744                         if (hasNext) {
    1745                             key = keySelector(enumerator.current());
    1746                             compareKey = compareSelector(key);
    1747                             group = [elementSelector(enumerator.current())];
    1748                         }
    1749                         else group = [];
    1750 
    1751                         return this.yieldReturn(result);
    1752                     }
    1753 
    1754                     return false;
    1755                 },
    1756                 function () { Utils.dispose(enumerator); });
    1757         });
    1758     };
    1759 
    1760     Enumerable.prototype.buffer = function (count) {
    1761         var source = this;
    1762 
    1763         return new Enumerable(function () {
    1764             var enumerator;
    1765 
    1766             return new IEnumerator(
    1767                 function () { enumerator = source.getEnumerator(); },
    1768                 function () {
    1769                     var array = [];
    1770                     var index = 0;
    1771                     while (enumerator.moveNext()) {
    1772                         array.push(enumerator.current());
    1773                         if (++index >= count) return this.yieldReturn(array);
    1774                     }
    1775                     if (array.length > 0) return this.yieldReturn(array);
    1776                     return false;
    1777                 },
    1778                 function () { Utils.dispose(enumerator); });
    1779         });
    1780     };
    1781 
    1782     /* Aggregate Methods */
    1783 
    1784     // Overload:function(func)
    1785     // Overload:function(seed,func)
    1786     // Overload:function(seed,func,resultSelector)
    1787     Enumerable.prototype.aggregate = function (seed, func, resultSelector) {
    1788         resultSelector = Utils.createLambda(resultSelector);
    1789         return resultSelector(this.scan(seed, func, resultSelector).last());
    1790     };
    1791 
    1792     // Overload:function()
    1793     // Overload:function(selector)
    1794     Enumerable.prototype.average = function (selector) {
    1795         selector = Utils.createLambda(selector);
    1796 
    1797         var sum = 0;
    1798         var count = 0;
    1799         this.forEach(function (x) {
    1800             sum += selector(x);
    1801             ++count;
    1802         });
    1803 
    1804         return sum / count;
    1805     };
    1806 
    1807     // Overload:function()
    1808     // Overload:function(predicate)
    1809     Enumerable.prototype.count = function (predicate) {
    1810         predicate = (predicate == null) ? Functions.True : Utils.createLambda(predicate);
    1811 
    1812         var count = 0;
    1813         this.forEach(function (x, i) {
    1814             if (predicate(x, i))++count;
    1815         });
    1816         return count;
    1817     };
    1818 
    1819     // Overload:function()
    1820     // Overload:function(selector)
    1821     Enumerable.prototype.max = function (selector) {
    1822         if (selector == null) selector = Functions.Identity;
    1823         return this.select(selector).aggregate(function (a, b) { return (a > b) ? a : b; });
    1824     };
    1825 
    1826     // Overload:function()
    1827     // Overload:function(selector)
    1828     Enumerable.prototype.min = function (selector) {
    1829         if (selector == null) selector = Functions.Identity;
    1830         return this.select(selector).aggregate(function (a, b) { return (a < b) ? a : b; });
    1831     };
    1832 
    1833     Enumerable.prototype.maxBy = function (keySelector) {
    1834         keySelector = Utils.createLambda(keySelector);
    1835         return this.aggregate(function (a, b) { return (keySelector(a) > keySelector(b)) ? a : b; });
    1836     };
    1837 
    1838     Enumerable.prototype.minBy = function (keySelector) {
    1839         keySelector = Utils.createLambda(keySelector);
    1840         return this.aggregate(function (a, b) { return (keySelector(a) < keySelector(b)) ? a : b; });
    1841     };
    1842 
    1843     // Overload:function()
    1844     // Overload:function(selector)
    1845     Enumerable.prototype.sum = function (selector) {
    1846         if (selector == null) selector = Functions.Identity;
    1847         return this.select(selector).aggregate(0, function (a, b) { return a + b; });
    1848     };
    1849 
    1850     /* Paging Methods */
    1851 
    1852     Enumerable.prototype.elementAt = function (index) {
    1853         var value;
    1854         var found = false;
    1855         this.forEach(function (x, i) {
    1856             if (i == index) {
    1857                 value = x;
    1858                 found = true;
    1859                 return false;
    1860             }
    1861         });
    1862 
    1863         if (!found) throw new Error("index is less than 0 or greater than or equal to the number of elements in source.");
    1864         return value;
    1865     };
    1866 
    1867     Enumerable.prototype.elementAtOrDefault = function (index, defaultValue) {
    1868         if (defaultValue === undefined) defaultValue = null;
    1869         var value;
    1870         var found = false;
    1871         this.forEach(function (x, i) {
    1872             if (i == index) {
    1873                 value = x;
    1874                 found = true;
    1875                 return false;
    1876             }
    1877         });
    1878 
    1879         return (!found) ? defaultValue : value;
    1880     };
    1881 
    1882     // Overload:function()
    1883     // Overload:function(predicate)
    1884     Enumerable.prototype.first = function (predicate) {
    1885         if (predicate != null) return this.where(predicate).first();
    1886 
    1887         var value;
    1888         var found = false;
    1889         this.forEach(function (x) {
    1890             value = x;
    1891             found = true;
    1892             return false;
    1893         });
    1894 
    1895         if (!found) throw new Error("first:No element satisfies the condition.");
    1896         return value;
    1897     };
    1898 
    1899     Enumerable.prototype.firstOrDefault = function (predicate, defaultValue) {
    1900         if (predicate !== undefined) {
    1901             if (typeof predicate === Types.Function || typeof Utils.createLambda(predicate) === Types.Function) {
    1902                 return this.where(predicate).firstOrDefault(undefined, defaultValue);
    1903             }
    1904             defaultValue = predicate;
    1905         }
    1906 
    1907         var value;
    1908         var found = false;
    1909         this.forEach(function (x) {
    1910             value = x;
    1911             found = true;
    1912             return false;
    1913         });
    1914         return (!found) ? defaultValue : value;
    1915     };
    1916 
    1917     // Overload:function()
    1918     // Overload:function(predicate)
    1919     Enumerable.prototype.last = function (predicate) {
    1920         if (predicate != null) return this.where(predicate).last();
    1921 
    1922         var value;
    1923         var found = false;
    1924         this.forEach(function (x) {
    1925             found = true;
    1926             value = x;
    1927         });
    1928 
    1929         if (!found) throw new Error("last:No element satisfies the condition.");
    1930         return value;
    1931     };
    1932 
    1933     Enumerable.prototype.lastOrDefault = function (predicate, defaultValue) {
    1934         if (predicate !== undefined) {
    1935             if (typeof predicate === Types.Function || typeof Utils.createLambda(predicate) === Types.Function) {
    1936                 return this.where(predicate).lastOrDefault(undefined, defaultValue);
    1937             }
    1938             defaultValue = predicate;
    1939         }
    1940 
    1941         var value;
    1942         var found = false;
    1943         this.forEach(function (x) {
    1944             found = true;
    1945             value = x;
    1946         });
    1947         return (!found) ? defaultValue : value;
    1948     };
    1949 
    1950     // Overload:function()
    1951     // Overload:function(predicate)
    1952     Enumerable.prototype.single = function (predicate) {
    1953         if (predicate != null) return this.where(predicate).single();
    1954 
    1955         var value;
    1956         var found = false;
    1957         this.forEach(function (x) {
    1958             if (!found) {
    1959                 found = true;
    1960                 value = x;
    1961             } else throw new Error("single:sequence contains more than one element.");
    1962         });
    1963 
    1964         if (!found) throw new Error("single:No element satisfies the condition.");
    1965         return value;
    1966     };
    1967 
    1968     // Overload:function(defaultValue)
    1969     // Overload:function(defaultValue,predicate)
    1970     Enumerable.prototype.singleOrDefault = function (predicate, defaultValue) {
    1971         if (defaultValue === undefined) defaultValue = null;
    1972         if (predicate != null) return this.where(predicate).singleOrDefault(null, defaultValue);
    1973 
    1974         var value;
    1975         var found = false;
    1976         this.forEach(function (x) {
    1977             if (!found) {
    1978                 found = true;
    1979                 value = x;
    1980             } else throw new Error("single:sequence contains more than one element.");
    1981         });
    1982 
    1983         return (!found) ? defaultValue : value;
    1984     };
    1985 
    1986     Enumerable.prototype.skip = function (count) {
    1987         var source = this;
    1988 
    1989         return new Enumerable(function () {
    1990             var enumerator;
    1991             var index = 0;
    1992 
    1993             return new IEnumerator(
    1994                 function () {
    1995                     enumerator = source.getEnumerator();
    1996                     while (index++ < count && enumerator.moveNext()) {
    1997                     }
    1998                     ;
    1999                 },
    2000                 function () {
    2001                     return (enumerator.moveNext())
    2002                         ? this.yieldReturn(enumerator.current())
    2003                         : false;
    2004                 },
    2005                 function () { Utils.dispose(enumerator); });
    2006         });
    2007     };
    2008 
    2009     // Overload:function(predicate<element>)
    2010     // Overload:function(predicate<element,index>)
    2011     Enumerable.prototype.skipWhile = function (predicate) {
    2012         predicate = Utils.createLambda(predicate);
    2013         var source = this;
    2014 
    2015         return new Enumerable(function () {
    2016             var enumerator;
    2017             var index = 0;
    2018             var isSkipEnd = false;
    2019 
    2020             return new IEnumerator(
    2021                 function () { enumerator = source.getEnumerator(); },
    2022                 function () {
    2023                     while (!isSkipEnd) {
    2024                         if (enumerator.moveNext()) {
    2025                             if (!predicate(enumerator.current(), index++)) {
    2026                                 isSkipEnd = true;
    2027                                 return this.yieldReturn(enumerator.current());
    2028                             }
    2029                             continue;
    2030                         } else return false;
    2031                     }
    2032 
    2033                     return (enumerator.moveNext())
    2034                         ? this.yieldReturn(enumerator.current())
    2035                         : false;
    2036 
    2037                 },
    2038                 function () { Utils.dispose(enumerator); });
    2039         });
    2040     };
    2041 
    2042     Enumerable.prototype.take = function (count) {
    2043         var source = this;
    2044 
    2045         return new Enumerable(function () {
    2046             var enumerator;
    2047             var index = 0;
    2048 
    2049             return new IEnumerator(
    2050                 function () { enumerator = source.getEnumerator(); },
    2051                 function () {
    2052                     return (index++ < count && enumerator.moveNext())
    2053                         ? this.yieldReturn(enumerator.current())
    2054                         : false;
    2055                 },
    2056                 function () { Utils.dispose(enumerator); }
    2057             );
    2058         });
    2059     };
    2060 
    2061     // Overload:function(predicate<element>)
    2062     // Overload:function(predicate<element,index>)
    2063     Enumerable.prototype.takeWhile = function (predicate) {
    2064         predicate = Utils.createLambda(predicate);
    2065         var source = this;
    2066 
    2067         return new Enumerable(function () {
    2068             var enumerator;
    2069             var index = 0;
    2070 
    2071             return new IEnumerator(
    2072                 function () { enumerator = source.getEnumerator(); },
    2073                 function () {
    2074                     return (enumerator.moveNext() && predicate(enumerator.current(), index++))
    2075                         ? this.yieldReturn(enumerator.current())
    2076                         : false;
    2077                 },
    2078                 function () { Utils.dispose(enumerator); });
    2079         });
    2080     };
    2081 
    2082     // Overload:function()
    2083     // Overload:function(count)
    2084     Enumerable.prototype.takeExceptLast = function (count) {
    2085         if (count == null) count = 1;
    2086         var source = this;
    2087 
    2088         return new Enumerable(function () {
    2089             if (count <= 0) return source.getEnumerator(); // do nothing
    2090 
    2091             var enumerator;
    2092             var q = [];
    2093 
    2094             return new IEnumerator(
    2095                 function () { enumerator = source.getEnumerator(); },
    2096                 function () {
    2097                     while (enumerator.moveNext()) {
    2098                         if (q.length == count) {
    2099                             q.push(enumerator.current());
    2100                             return this.yieldReturn(q.shift());
    2101                         }
    2102                         q.push(enumerator.current());
    2103                     }
    2104                     return false;
    2105                 },
    2106                 function () { Utils.dispose(enumerator); });
    2107         });
    2108     };
    2109 
    2110     Enumerable.prototype.takeFromLast = function (count) {
    2111         if (count <= 0 || count == null) return Enumerable.empty();
    2112         var source = this;
    2113 
    2114         return new Enumerable(function () {
    2115             var sourceEnumerator;
    2116             var enumerator;
    2117             var q = [];
    2118 
    2119             return new IEnumerator(
    2120                 function () { sourceEnumerator = source.getEnumerator(); },
    2121                 function () {
    2122                     while (sourceEnumerator.moveNext()) {
    2123                         if (q.length == count) q.shift();
    2124                         q.push(sourceEnumerator.current());
    2125                     }
    2126                     if (enumerator == null) {
    2127                         enumerator = Enumerable.from(q).getEnumerator();
    2128                     }
    2129                     return (enumerator.moveNext())
    2130                         ? this.yieldReturn(enumerator.current())
    2131                         : false;
    2132                 },
    2133                 function () { Utils.dispose(enumerator); });
    2134         });
    2135     };
    2136 
    2137     // Overload:function(item)
    2138     // Overload:function(predicate)
    2139     Enumerable.prototype.indexOf = function (item) {
    2140         var found = null;
    2141 
    2142         // item as predicate
    2143         if (typeof (item) === Types.Function) {
    2144             this.forEach(function (x, i) {
    2145                 if (item(x, i)) {
    2146                     found = i;
    2147                     return false;
    2148                 }
    2149             });
    2150         }
    2151         else {
    2152             this.forEach(function (x, i) {
    2153                 if (x === item) {
    2154                     found = i;
    2155                     return false;
    2156                 }
    2157             });
    2158         }
    2159 
    2160         return (found !== null) ? found : -1;
    2161     };
    2162 
    2163     // Overload:function(item)
    2164     // Overload:function(predicate)
    2165     Enumerable.prototype.lastIndexOf = function (item) {
    2166         var result = -1;
    2167 
    2168         // item as predicate
    2169         if (typeof (item) === Types.Function) {
    2170             this.forEach(function (x, i) {
    2171                 if (item(x, i)) result = i;
    2172             });
    2173         }
    2174         else {
    2175             this.forEach(function (x, i) {
    2176                 if (x === item) result = i;
    2177             });
    2178         }
    2179 
    2180         return result;
    2181     };
    2182 
    2183     /* Convert Methods */
    2184 
    2185     Enumerable.prototype.cast = function () {
    2186         return this;
    2187     };
    2188 
    2189     Enumerable.prototype.asEnumerable = function () {
    2190         return Enumerable.from(this);
    2191     };
    2192 
    2193     Enumerable.prototype.toArray = function () {
    2194         var array = [];
    2195         this.forEach(function (x) { array.push(x); });
    2196         return array;
    2197     };
    2198 
    2199     // Overload:function(keySelector)
    2200     // Overload:function(keySelector, elementSelector)
    2201     // Overload:function(keySelector, elementSelector, compareSelector)
    2202     Enumerable.prototype.toLookup = function (keySelector, elementSelector, compareSelector) {
    2203         keySelector = Utils.createLambda(keySelector);
    2204         elementSelector = Utils.createLambda(elementSelector);
    2205         compareSelector = Utils.createLambda(compareSelector);
    2206 
    2207         var dict = new Dictionary(compareSelector);
    2208         this.forEach(function (x) {
    2209             var key = keySelector(x);
    2210             var element = elementSelector(x);
    2211 
    2212             var array = dict.get(key);
    2213             if (array !== undefined) array.push(element);
    2214             else dict.add(key, [element]);
    2215         });
    2216         return new Lookup(dict);
    2217     };
    2218 
    2219     Enumerable.prototype.toObject = function (keySelector, elementSelector) {
    2220         keySelector = Utils.createLambda(keySelector);
    2221         elementSelector = Utils.createLambda(elementSelector);
    2222 
    2223         var obj = {};
    2224         this.forEach(function (x) {
    2225             obj[keySelector(x)] = elementSelector(x);
    2226         });
    2227         return obj;
    2228     };
    2229 
    2230     // Overload:function(keySelector, elementSelector)
    2231     // Overload:function(keySelector, elementSelector, compareSelector)
    2232     Enumerable.prototype.toDictionary = function (keySelector, elementSelector, compareSelector) {
    2233         keySelector = Utils.createLambda(keySelector);
    2234         elementSelector = Utils.createLambda(elementSelector);
    2235         compareSelector = Utils.createLambda(compareSelector);
    2236 
    2237         var dict = new Dictionary(compareSelector);
    2238         this.forEach(function (x) {
    2239             dict.add(keySelector(x), elementSelector(x));
    2240         });
    2241         return dict;
    2242     };
    2243 
    2244     // Overload:function()
    2245     // Overload:function(replacer)
    2246     // Overload:function(replacer, space)
    2247     Enumerable.prototype.toJSONString = function (replacer, space) {
    2248         if (typeof JSON === Types.Undefined || JSON.stringify == null) {
    2249             throw new Error("toJSONString can't find JSON.stringify. This works native JSON support Browser or include json2.js");
    2250         }
    2251         return JSON.stringify(this.toArray(), replacer, space);
    2252     };
    2253 
    2254     // Overload:function()
    2255     // Overload:function(separator)
    2256     // Overload:function(separator,selector)
    2257     Enumerable.prototype.toJoinedString = function (separator, selector) {
    2258         if (separator == null) separator = "";
    2259         if (selector == null) selector = Functions.Identity;
    2260 
    2261         return this.select(selector).toArray().join(separator);
    2262     };
    2263 
    2264 
    2265     /* Action Methods */
    2266 
    2267     // Overload:function(action<element>)
    2268     // Overload:function(action<element,index>)
    2269     Enumerable.prototype.doAction = function (action) {
    2270         var source = this;
    2271         action = Utils.createLambda(action);
    2272 
    2273         return new Enumerable(function () {
    2274             var enumerator;
    2275             var index = 0;
    2276 
    2277             return new IEnumerator(
    2278                 function () { enumerator = source.getEnumerator(); },
    2279                 function () {
    2280                     if (enumerator.moveNext()) {
    2281                         action(enumerator.current(), index++);
    2282                         return this.yieldReturn(enumerator.current());
    2283                     }
    2284                     return false;
    2285                 },
    2286                 function () { Utils.dispose(enumerator); });
    2287         });
    2288     };
    2289 
    2290     // Overload:function(action<element>)
    2291     // Overload:function(action<element,index>)
    2292     // Overload:function(func<element,bool>)
    2293     // Overload:function(func<element,index,bool>)
    2294     Enumerable.prototype.forEach = function (action) {
    2295         action = Utils.createLambda(action);
    2296 
    2297         var index = 0;
    2298         var enumerator = this.getEnumerator();
    2299         try {
    2300             while (enumerator.moveNext()) {
    2301                 if (action(enumerator.current(), index++) === false) break;
    2302             }
    2303         } finally {
    2304             Utils.dispose(enumerator);
    2305         }
    2306     };
    2307 
    2308     // Overload:function()
    2309     // Overload:function(separator)
    2310     // Overload:function(separator,selector)
    2311     Enumerable.prototype.write = function (separator, selector) {
    2312         if (separator == null) separator = "";
    2313         selector = Utils.createLambda(selector);
    2314 
    2315         var isFirst = true;
    2316         this.forEach(function (item) {
    2317             if (isFirst) isFirst = false;
    2318             else document.write(separator);
    2319             document.write(selector(item));
    2320         });
    2321     };
    2322 
    2323     // Overload:function()
    2324     // Overload:function(selector)
    2325     Enumerable.prototype.writeLine = function (selector) {
    2326         selector = Utils.createLambda(selector);
    2327 
    2328         this.forEach(function (item) {
    2329             document.writeln(selector(item) + "<br />");
    2330         });
    2331     };
    2332 
    2333     Enumerable.prototype.force = function () {
    2334         var enumerator = this.getEnumerator();
    2335 
    2336         try {
    2337             while (enumerator.moveNext()) {
    2338             }
    2339         }
    2340         finally {
    2341             Utils.dispose(enumerator);
    2342         }
    2343     };
    2344 
    2345     /* Functional Methods */
    2346 
    2347     Enumerable.prototype.letBind = function (func) {
    2348         func = Utils.createLambda(func);
    2349         var source = this;
    2350 
    2351         return new Enumerable(function () {
    2352             var enumerator;
    2353 
    2354             return new IEnumerator(
    2355                 function () {
    2356                     enumerator = Enumerable.from(func(source)).getEnumerator();
    2357                 },
    2358                 function () {
    2359                     return (enumerator.moveNext())
    2360                         ? this.yieldReturn(enumerator.current())
    2361                         : false;
    2362                 },
    2363                 function () { Utils.dispose(enumerator); });
    2364         });
    2365     };
    2366 
    2367     Enumerable.prototype.share = function () {
    2368         var source = this;
    2369         var sharedEnumerator;
    2370         var disposed = false;
    2371 
    2372         return new DisposableEnumerable(function () {
    2373             return new IEnumerator(
    2374                 function () {
    2375                     if (sharedEnumerator == null) {
    2376                         sharedEnumerator = source.getEnumerator();
    2377                     }
    2378                 },
    2379                 function () {
    2380                     if (disposed) throw new Error("enumerator is disposed");
    2381 
    2382                     return (sharedEnumerator.moveNext())
    2383                         ? this.yieldReturn(sharedEnumerator.current())
    2384                         : false;
    2385                 },
    2386                 Functions.Blank
    2387             );
    2388         }, function () {
    2389             disposed = true;
    2390             Utils.dispose(sharedEnumerator);
    2391         });
    2392     };
    2393 
    2394     Enumerable.prototype.memoize = function () {
    2395         var source = this;
    2396         var cache;
    2397         var enumerator;
    2398         var disposed = false;
    2399 
    2400         return new DisposableEnumerable(function () {
    2401             var index = -1;
    2402 
    2403             return new IEnumerator(
    2404                 function () {
    2405                     if (enumerator == null) {
    2406                         enumerator = source.getEnumerator();
    2407                         cache = [];
    2408                     }
    2409                 },
    2410                 function () {
    2411                     if (disposed) throw new Error("enumerator is disposed");
    2412 
    2413                     index++;
    2414                     if (cache.length <= index) {
    2415                         return (enumerator.moveNext())
    2416                             ? this.yieldReturn(cache[index] = enumerator.current())
    2417                             : false;
    2418                     }
    2419 
    2420                     return this.yieldReturn(cache[index]);
    2421                 },
    2422                 Functions.Blank
    2423             );
    2424         }, function () {
    2425             disposed = true;
    2426             Utils.dispose(enumerator);
    2427             cache = null;
    2428         });
    2429     };
    2430 
    2431     /* Iterator (ES6 for..of) support */
    2432     if (Utils.hasNativeIteratorSupport()) {
    2433         Enumerable.prototype[Symbol.iterator] = function () {
    2434             return {
    2435                 enumerator: this.getEnumerator(),
    2436                 next: function () {
    2437                     if (this.enumerator.moveNext()) {
    2438                         return {
    2439                             done: false,
    2440                             value: this.enumerator.current()
    2441                         };
    2442                     } else {
    2443                         return { done: true };
    2444                     }
    2445                 }
    2446             };
    2447         };
    2448     }
    2449 
    2450     /* Error Handling Methods */
    2451 
    2452     Enumerable.prototype.catchError = function (handler) {
    2453         handler = Utils.createLambda(handler);
    2454         var source = this;
    2455 
    2456         return new Enumerable(function () {
    2457             var enumerator;
    2458 
    2459             return new IEnumerator(
    2460                 function () { enumerator = source.getEnumerator(); },
    2461                 function () {
    2462                     try {
    2463                         return (enumerator.moveNext())
    2464                             ? this.yieldReturn(enumerator.current())
    2465                             : false;
    2466                     } catch (e) {
    2467                         handler(e);
    2468                         return false;
    2469                     }
    2470                 },
    2471                 function () { Utils.dispose(enumerator); });
    2472         });
    2473     };
    2474 
    2475     Enumerable.prototype.finallyAction = function (finallyAction) {
    2476         finallyAction = Utils.createLambda(finallyAction);
    2477         var source = this;
    2478 
    2479         return new Enumerable(function () {
    2480             var enumerator;
    2481 
    2482             return new IEnumerator(
    2483                 function () { enumerator = source.getEnumerator(); },
    2484                 function () {
    2485                     return (enumerator.moveNext())
    2486                         ? this.yieldReturn(enumerator.current())
    2487                         : false;
    2488                 },
    2489                 function () {
    2490                     try {
    2491                         Utils.dispose(enumerator);
    2492                     } finally {
    2493                         finallyAction();
    2494                     }
    2495                 });
    2496         });
    2497     };
    2498 
    2499     /* For Debug Methods */
    2500 
    2501     // Overload:function()
    2502     // Overload:function(selector)
    2503     Enumerable.prototype.log = function (selector) {
    2504         selector = Utils.createLambda(selector);
    2505 
    2506         return this.doAction(function (item) {
    2507             if (typeof console !== Types.Undefined) {
    2508                 console.log(selector(item));
    2509             }
    2510         });
    2511     };
    2512 
    2513     // Overload:function()
    2514     // Overload:function(message)
    2515     // Overload:function(message,selector)
    2516     Enumerable.prototype.trace = function (message, selector) {
    2517         if (message == null) message = "Trace";
    2518         selector = Utils.createLambda(selector);
    2519 
    2520         return this.doAction(function (item) {
    2521             if (typeof console !== Types.Undefined) {
    2522                 console.log(message, selector(item));
    2523             }
    2524         });
    2525     };
    2526 
    2527     // private
    2528 
    2529     var OrderedEnumerable = function (source, keySelector, comparer, descending, parent) {
    2530         this.source = source;
    2531         this.keySelector = Utils.createLambda(keySelector);
    2532         this.descending = descending;
    2533         this.parent = parent;
    2534 
    2535         if (comparer)
    2536             this.comparer = Utils.createLambda(comparer);
    2537     };
    2538     OrderedEnumerable.prototype = new Enumerable();
    2539 
    2540     OrderedEnumerable.prototype.createOrderedEnumerable = function (keySelector, comparer, descending) {
    2541         return new OrderedEnumerable(this.source, keySelector, comparer, descending, this);
    2542     };
    2543 
    2544     OrderedEnumerable.prototype.thenBy = function (keySelector, comparer) {
    2545         return this.createOrderedEnumerable(keySelector, comparer, false);
    2546     };
    2547 
    2548     OrderedEnumerable.prototype.thenByDescending = function (keySelector, comparer) {
    2549         return this.createOrderedEnumerable(keySelector, comparer, true);
    2550     };
    2551 
    2552     OrderedEnumerable.prototype.getEnumerator = function () {
    2553         var self = this;
    2554         var buffer;
    2555         var indexes;
    2556         var index = 0;
    2557 
    2558         return new IEnumerator(
    2559             function () {
    2560                 buffer = [];
    2561                 indexes = [];
    2562                 self.source.forEach(function (item, index) {
    2563                     buffer.push(item);
    2564                     indexes.push(index);
    2565                 });
    2566                 var sortContext = SortContext.create(self, null);
    2567                 sortContext.GenerateKeys(buffer);
    2568 
    2569                 indexes.sort(function (a, b) { return sortContext.compare(a, b); });
    2570             },
    2571             function () {
    2572                 return (index < indexes.length)
    2573                     ? this.yieldReturn(buffer[indexes[index++]])
    2574                     : false;
    2575             },
    2576             Functions.Blank
    2577         );
    2578     };
    2579 
    2580     var SortContext = function (keySelector, comparer, descending, child) {
    2581         this.keySelector = keySelector;
    2582         this.descending = descending;
    2583         this.child = child;
    2584         this.comparer = comparer;
    2585         this.keys = null;
    2586     };
    2587 
    2588     SortContext.create = function (orderedEnumerable, currentContext) {
    2589         var context = new SortContext(
    2590             orderedEnumerable.keySelector, orderedEnumerable.comparer, orderedEnumerable.descending, currentContext
    2591         );
    2592 
    2593         if (orderedEnumerable.parent != null) return SortContext.create(orderedEnumerable.parent, context);
    2594         return context;
    2595     };
    2596 
    2597     SortContext.prototype.GenerateKeys = function (source) {
    2598         var len = source.length;
    2599         var keySelector = this.keySelector;
    2600         var keys = new Array(len);
    2601         for (var i = 0; i < len; i++) keys[i] = keySelector(source[i]);
    2602         this.keys = keys;
    2603 
    2604         if (this.child != null) this.child.GenerateKeys(source);
    2605     };
    2606 
    2607     SortContext.prototype.compare = function (index1, index2) {
    2608         var comparison = this.comparer ?
    2609             this.comparer(this.keys[index1], this.keys[index2]) :
    2610             Utils.compare(this.keys[index1], this.keys[index2]);
    2611 
    2612         if (comparison == 0) {
    2613             if (this.child != null) return this.child.compare(index1, index2);
    2614             return Utils.compare(index1, index2);
    2615         }
    2616 
    2617         return (this.descending) ? -comparison : comparison;
    2618     };
    2619 
    2620     var DisposableEnumerable = function (getEnumerator, dispose) {
    2621         this.dispose = dispose;
    2622         Enumerable.call(this, getEnumerator);
    2623     };
    2624     DisposableEnumerable.prototype = new Enumerable();
    2625 
    2626     // optimize array or arraylike object
    2627 
    2628     var ArrayEnumerable = function (source) {
    2629         this.getSource = function () { return source; };
    2630     };
    2631     ArrayEnumerable.prototype = new Enumerable();
    2632 
    2633     ArrayEnumerable.prototype.any = function (predicate) {
    2634         return (predicate == null)
    2635             ? (this.getSource().length > 0)
    2636             : Enumerable.prototype.any.apply(this, arguments);
    2637     };
    2638 
    2639     ArrayEnumerable.prototype.count = function (predicate) {
    2640         return (predicate == null)
    2641             ? this.getSource().length
    2642             : Enumerable.prototype.count.apply(this, arguments);
    2643     };
    2644 
    2645     ArrayEnumerable.prototype.elementAt = function (index) {
    2646         var source = this.getSource();
    2647         return (0 <= index && index < source.length)
    2648             ? source[index]
    2649             : Enumerable.prototype.elementAt.apply(this, arguments);
    2650     };
    2651 
    2652     ArrayEnumerable.prototype.elementAtOrDefault = function (index, defaultValue) {
    2653         if (defaultValue === undefined) defaultValue = null;
    2654         var source = this.getSource();
    2655         return (0 <= index && index < source.length)
    2656             ? source[index]
    2657             : defaultValue;
    2658     };
    2659 
    2660     ArrayEnumerable.prototype.first = function (predicate) {
    2661         var source = this.getSource();
    2662         return (predicate == null && source.length > 0)
    2663             ? source[0]
    2664             : Enumerable.prototype.first.apply(this, arguments);
    2665     };
    2666 
    2667     ArrayEnumerable.prototype.firstOrDefault = function (predicate, defaultValue) {
    2668         if (predicate !== undefined) {
    2669             return Enumerable.prototype.firstOrDefault.apply(this, arguments);
    2670         }
    2671         defaultValue = predicate;
    2672 
    2673         var source = this.getSource();
    2674         return source.length > 0 ? source[0] : defaultValue;
    2675     };
    2676 
    2677     ArrayEnumerable.prototype.last = function (predicate) {
    2678         var source = this.getSource();
    2679         return (predicate == null && source.length > 0)
    2680             ? source[source.length - 1]
    2681             : Enumerable.prototype.last.apply(this, arguments);
    2682     };
    2683 
    2684     ArrayEnumerable.prototype.lastOrDefault = function (predicate, defaultValue) {
    2685         if (predicate !== undefined) {
    2686             return Enumerable.prototype.lastOrDefault.apply(this, arguments);
    2687         }
    2688         defaultValue = predicate;
    2689 
    2690         var source = this.getSource();
    2691         return source.length > 0 ? source[source.length - 1] : defaultValue;
    2692     };
    2693 
    2694     ArrayEnumerable.prototype.skip = function (count) {
    2695         var source = this.getSource();
    2696 
    2697         return new Enumerable(function () {
    2698             var index;
    2699 
    2700             return new IEnumerator(
    2701                 function () { index = (count < 0) ? 0 : count; },
    2702                 function () {
    2703                     return (index < source.length)
    2704                         ? this.yieldReturn(source[index++])
    2705                         : false;
    2706                 },
    2707                 Functions.Blank);
    2708         });
    2709     };
    2710 
    2711     ArrayEnumerable.prototype.takeExceptLast = function (count) {
    2712         if (count == null) count = 1;
    2713         return this.take(this.getSource().length - count);
    2714     };
    2715 
    2716     ArrayEnumerable.prototype.takeFromLast = function (count) {
    2717         return this.skip(this.getSource().length - count);
    2718     };
    2719 
    2720     ArrayEnumerable.prototype.reverse = function () {
    2721         var source = this.getSource();
    2722 
    2723         return new Enumerable(function () {
    2724             var index;
    2725 
    2726             return new IEnumerator(
    2727                 function () {
    2728                     index = source.length;
    2729                 },
    2730                 function () {
    2731                     return (index > 0)
    2732                         ? this.yieldReturn(source[--index])
    2733                         : false;
    2734                 },
    2735                 Functions.Blank);
    2736         });
    2737     };
    2738 
    2739     ArrayEnumerable.prototype.sequenceEqual = function (second, compareSelector) {
    2740         if ((second instanceof ArrayEnumerable || second instanceof Array)
    2741             && compareSelector == null
    2742             && Enumerable.from(second).count() != this.count()) {
    2743             return false;
    2744         }
    2745 
    2746         return Enumerable.prototype.sequenceEqual.apply(this, arguments);
    2747     };
    2748 
    2749     ArrayEnumerable.prototype.toJoinedString = function (separator, selector) {
    2750         var source = this.getSource();
    2751         if (selector != null || !(source instanceof Array)) {
    2752             return Enumerable.prototype.toJoinedString.apply(this, arguments);
    2753         }
    2754 
    2755         if (separator == null) separator = "";
    2756         return source.join(separator);
    2757     };
    2758 
    2759     ArrayEnumerable.prototype.getEnumerator = function () {
    2760         var source = this.getSource();
    2761         var index = -1;
    2762 
    2763         // fast and simple enumerator
    2764         return {
    2765             current: function () { return source[index]; },
    2766             moveNext: function () {
    2767                 return ++index < source.length;
    2768             },
    2769             dispose: Functions.Blank
    2770         };
    2771     };
    2772 
    2773     // optimization for multiple where and multiple select and whereselect
    2774 
    2775     var WhereEnumerable = function (source, predicate) {
    2776         this.prevSource = source;
    2777         this.prevPredicate = predicate; // predicate.length always <= 1
    2778     };
    2779     WhereEnumerable.prototype = new Enumerable();
    2780 
    2781     WhereEnumerable.prototype.where = function (predicate) {
    2782         predicate = Utils.createLambda(predicate);
    2783 
    2784         if (predicate.length <= 1) {
    2785             var prevPredicate = this.prevPredicate;
    2786             var composedPredicate = function (x) { return prevPredicate(x) && predicate(x); };
    2787             return new WhereEnumerable(this.prevSource, composedPredicate);
    2788         }
    2789         else {
    2790             // if predicate use index, can't compose
    2791             return Enumerable.prototype.where.call(this, predicate);
    2792         }
    2793     };
    2794 
    2795     WhereEnumerable.prototype.select = function (selector) {
    2796         selector = Utils.createLambda(selector);
    2797 
    2798         return (selector.length <= 1)
    2799             ? new WhereSelectEnumerable(this.prevSource, this.prevPredicate, selector)
    2800             : Enumerable.prototype.select.call(this, selector);
    2801     };
    2802 
    2803     WhereEnumerable.prototype.getEnumerator = function () {
    2804         var predicate = this.prevPredicate;
    2805         var source = this.prevSource;
    2806         var enumerator;
    2807 
    2808         return new IEnumerator(
    2809             function () { enumerator = source.getEnumerator(); },
    2810             function () {
    2811                 while (enumerator.moveNext()) {
    2812                     if (predicate(enumerator.current())) {
    2813                         return this.yieldReturn(enumerator.current());
    2814                     }
    2815                 }
    2816                 return false;
    2817             },
    2818             function () { Utils.dispose(enumerator); });
    2819     };
    2820 
    2821     var WhereSelectEnumerable = function (source, predicate, selector) {
    2822         this.prevSource = source;
    2823         this.prevPredicate = predicate; // predicate.length always <= 1 or null
    2824         this.prevSelector = selector; // selector.length always <= 1
    2825     };
    2826     WhereSelectEnumerable.prototype = new Enumerable();
    2827 
    2828     WhereSelectEnumerable.prototype.where = function (predicate) {
    2829         predicate = Utils.createLambda(predicate);
    2830 
    2831         return (predicate.length <= 1)
    2832             ? new WhereEnumerable(this, predicate)
    2833             : Enumerable.prototype.where.call(this, predicate);
    2834     };
    2835 
    2836     WhereSelectEnumerable.prototype.select = function (selector) {
    2837         selector = Utils.createLambda(selector);
    2838 
    2839         if (selector.length <= 1) {
    2840             var prevSelector = this.prevSelector;
    2841             var composedSelector = function (x) { return selector(prevSelector(x)); };
    2842             return new WhereSelectEnumerable(this.prevSource, this.prevPredicate, composedSelector);
    2843         }
    2844         else {
    2845             // if selector use index, can't compose
    2846             return Enumerable.prototype.select.call(this, selector);
    2847         }
    2848     };
    2849 
    2850     WhereSelectEnumerable.prototype.getEnumerator = function () {
    2851         var predicate = this.prevPredicate;
    2852         var selector = this.prevSelector;
    2853         var source = this.prevSource;
    2854         var enumerator;
    2855 
    2856         return new IEnumerator(
    2857             function () { enumerator = source.getEnumerator(); },
    2858             function () {
    2859                 while (enumerator.moveNext()) {
    2860                     if (predicate == null || predicate(enumerator.current())) {
    2861                         return this.yieldReturn(selector(enumerator.current()));
    2862                     }
    2863                 }
    2864                 return false;
    2865             },
    2866             function () { Utils.dispose(enumerator); });
    2867     };
    2868 
    2869     // Collections
    2870 
    2871     var Dictionary = (function () {
    2872         // static utility methods
    2873         var callHasOwnProperty = function (target, key) {
    2874             return Object.prototype.hasOwnProperty.call(target, key);
    2875         };
    2876 
    2877         var computeHashCode = function (obj) {
    2878             if (obj === null) return "null";
    2879             if (obj === undefined) return "undefined";
    2880 
    2881             return (typeof obj.toString === Types.Function)
    2882                 ? obj.toString()
    2883                 : Object.prototype.toString.call(obj);
    2884         };
    2885 
    2886         // LinkedList for Dictionary
    2887         var HashEntry = function (key, value) {
    2888             this.key = key;
    2889             this.value = value;
    2890             this.prev = null;
    2891             this.next = null;
    2892         };
    2893 
    2894         var EntryList = function () {
    2895             this.first = null;
    2896             this.last = null;
    2897         };
    2898         EntryList.prototype =
    2899         {
    2900             addLast: function (entry) {
    2901                 if (this.last != null) {
    2902                     this.last.next = entry;
    2903                     entry.prev = this.last;
    2904                     this.last = entry;
    2905                 } else this.first = this.last = entry;
    2906             },
    2907 
    2908             replace: function (entry, newEntry) {
    2909                 if (entry.prev != null) {
    2910                     entry.prev.next = newEntry;
    2911                     newEntry.prev = entry.prev;
    2912                 } else this.first = newEntry;
    2913 
    2914                 if (entry.next != null) {
    2915                     entry.next.prev = newEntry;
    2916                     newEntry.next = entry.next;
    2917                 } else this.last = newEntry;
    2918 
    2919             },
    2920 
    2921             remove: function (entry) {
    2922                 if (entry.prev != null) entry.prev.next = entry.next;
    2923                 else this.first = entry.next;
    2924 
    2925                 if (entry.next != null) entry.next.prev = entry.prev;
    2926                 else this.last = entry.prev;
    2927             }
    2928         };
    2929 
    2930         // Overload:function()
    2931         // Overload:function(compareSelector)
    2932         var Dictionary = function (compareSelector) {
    2933             this.countField = 0;
    2934             this.entryList = new EntryList();
    2935             this.buckets = {}; // as Dictionary<string,List<object>>
    2936             this.compareSelector = (compareSelector == null) ? Functions.Identity : compareSelector;
    2937         };
    2938         Dictionary.prototype =
    2939         {
    2940             add: function (key, value) {
    2941                 var compareKey = this.compareSelector(key);
    2942                 var hash = computeHashCode(compareKey);
    2943                 var entry = new HashEntry(key, value);
    2944                 if (callHasOwnProperty(this.buckets, hash)) {
    2945                     var array = this.buckets[hash];
    2946                     for (var i = 0; i < array.length; i++) {
    2947                         if (this.compareSelector(array[i].key) === compareKey) {
    2948                             this.entryList.replace(array[i], entry);
    2949                             array[i] = entry;
    2950                             return;
    2951                         }
    2952                     }
    2953                     array.push(entry);
    2954                 } else {
    2955                     this.buckets[hash] = [entry];
    2956                 }
    2957                 this.countField++;
    2958                 this.entryList.addLast(entry);
    2959             },
    2960 
    2961             get: function (key) {
    2962                 var compareKey = this.compareSelector(key);
    2963                 var hash = computeHashCode(compareKey);
    2964                 if (!callHasOwnProperty(this.buckets, hash)) return undefined;
    2965 
    2966                 var array = this.buckets[hash];
    2967                 for (var i = 0; i < array.length; i++) {
    2968                     var entry = array[i];
    2969                     if (this.compareSelector(entry.key) === compareKey) return entry.value;
    2970                 }
    2971                 return undefined;
    2972             },
    2973 
    2974             set: function (key, value) {
    2975                 var compareKey = this.compareSelector(key);
    2976                 var hash = computeHashCode(compareKey);
    2977                 if (callHasOwnProperty(this.buckets, hash)) {
    2978                     var array = this.buckets[hash];
    2979                     for (var i = 0; i < array.length; i++) {
    2980                         if (this.compareSelector(array[i].key) === compareKey) {
    2981                             var newEntry = new HashEntry(key, value);
    2982                             this.entryList.replace(array[i], newEntry);
    2983                             array[i] = newEntry;
    2984                             return true;
    2985                         }
    2986                     }
    2987                 }
    2988                 return false;
    2989             },
    2990 
    2991             contains: function (key) {
    2992                 var compareKey = this.compareSelector(key);
    2993                 var hash = computeHashCode(compareKey);
    2994                 if (!callHasOwnProperty(this.buckets, hash)) return false;
    2995 
    2996                 var array = this.buckets[hash];
    2997                 for (var i = 0; i < array.length; i++) {
    2998                     if (this.compareSelector(array[i].key) === compareKey) return true;
    2999                 }
    3000                 return false;
    3001             },
    3002 
    3003             clear: function () {
    3004                 this.countField = 0;
    3005                 this.buckets = {};
    3006                 this.entryList = new EntryList();
    3007             },
    3008 
    3009             remove: function (key) {
    3010                 var compareKey = this.compareSelector(key);
    3011                 var hash = computeHashCode(compareKey);
    3012                 if (!callHasOwnProperty(this.buckets, hash)) return;
    3013 
    3014                 var array = this.buckets[hash];
    3015                 for (var i = 0; i < array.length; i++) {
    3016                     if (this.compareSelector(array[i].key) === compareKey) {
    3017                         this.entryList.remove(array[i]);
    3018                         array.splice(i, 1);
    3019                         if (array.length == 0) delete this.buckets[hash];
    3020                         this.countField--;
    3021                         return;
    3022                     }
    3023                 }
    3024             },
    3025 
    3026             count: function () {
    3027                 return this.countField;
    3028             },
    3029 
    3030             toEnumerable: function () {
    3031                 var self = this;
    3032                 return new Enumerable(function () {
    3033                     var currentEntry;
    3034 
    3035                     return new IEnumerator(
    3036                         function () { currentEntry = self.entryList.first; },
    3037                         function () {
    3038                             if (currentEntry != null) {
    3039                                 var result = { key: currentEntry.key, value: currentEntry.value };
    3040                                 currentEntry = currentEntry.next;
    3041                                 return this.yieldReturn(result);
    3042                             }
    3043                             return false;
    3044                         },
    3045                         Functions.Blank);
    3046                 });
    3047             }
    3048         };
    3049 
    3050         return Dictionary;
    3051     })();
    3052 
    3053     // dictionary = Dictionary<TKey, TValue[]>
    3054     var Lookup = function (dictionary) {
    3055         this.count = function () {
    3056             return dictionary.count();
    3057         };
    3058         this.get = function (key) {
    3059             return Enumerable.from(dictionary.get(key));
    3060         };
    3061         this.contains = function (key) {
    3062             return dictionary.contains(key);
    3063         };
    3064         this.toEnumerable = function () {
    3065             return dictionary.toEnumerable().select(function (kvp) {
    3066                 return new Grouping(kvp.key, kvp.value);
    3067             });
    3068         };
    3069     };
    3070 
    3071     var Grouping = function (groupKey, elements) {
    3072         this.key = function () {
    3073             return groupKey;
    3074         };
    3075         ArrayEnumerable.call(this, elements);
    3076     };
    3077     Grouping.prototype = new ArrayEnumerable();
    3078 
    3079     // module export
    3080     if (typeof define === Types.Function && define.amd) { // AMD
    3081         define("linqjs", [], function () { return Enumerable; });
    3082     }
    3083     else if (typeof module !== Types.Undefined && module.exports) { // Node
    3084         module.exports = Enumerable;
    3085     }
    3086     else {
    3087         root.Enumerable = Enumerable;
    3088     }
    3089 })(this);
    View Code

    只需要将它的代码粘贴到 WPS 宏编辑器中一个新建的模块,即可使用。

    下面是我用 linq.js 以及自定义的 OfficeCollectionIterator 迭代器类,进行的一个查询测试(数据是由前面的 XLSExample 测试例子制备的)(因为使用了全局表达式,请将【工具】》【选项】》【编译】》【禁止全局作用域表达式】取消勾选):

     1 /*将 Office 集合对象封装成可迭代对象*/
     2 class OfficeCollectionIterator {
     3     constructor(collection) {
     4         if (collection == null ||
     5             collection == undefined ||
     6             typeof collection.Count != 'number' ||
     7             typeof collection.Item != 'function')
     8             throw new TypeError('参数 collection 必须是一个 Office 集合对象');
     9             
    10         this.collection = collection;
    11         this.index = 1;
    12     }
    13     
    14     [Symbol.iterator]() {
    15         return this;
    16     }
    17     
    18     next() {
    19         if (this.index <= this.collection.Count)
    20             return { done : false,
    21                 value : this.collection.Item(this.index++)
    22             };
    23         else
    24             return { done : true }; 
    25     }
    26     
    27     /*重置迭代器,以方便重新迭代*/
    28     reset() {
    29         this.index = 1;
    30     }
    31     
    32     /*是否已经迭代结束*/
    33     get isEnd() {
    34         return this.index > this.collection.Count;
    35     }
    36 }
    37 //linq.js 
    38 //来自:https://github.com/mihaifm/linq
    39 //功能:可以对任何可迭代对象进行查询
    40 //源型:C# 或说 .Net 的 Linq(语言集成查询)
    41 function linq_js_Test() {
    42     //查找表头单元格:当前表中有一个表以及其它杂乱单元格
    43     let usedRange = new OfficeCollectionIterator(
    44         ActiveSheet.UsedRange.Cells);
    45     let headerCells = Enumerable.from(usedRange)
    46         .where(cell => cell.Font.Bold == true)
    47         .where(cell => cell.Borders.Item(xlEdgeTop)
    48             .Weight == xlMedium)
    49         .select(cell => cell.Address())
    50         .toArray();
    51     Console.log(headerCells.join(';'));
    52 }

    其输出如下:

    $B$2;$C$2;$D$2;$E$2;$F$2;$G$2

    因为宏编程其实就是在以编程的方式,对应用程序宿主公布给宏代码的对象以及集合打交道,操作无外乎增删改查。

    有了 linq 这个库,我们就可以摆脱 var/for/if 这种散乱的拼凑的代码,而以 linq 的语义化的、直观的形式来编写我们想要的查询逻辑。

     

  • 相关阅读:
    版本控制,django缓存,跨域问题解决
    Linux之文件系统结构
    Linux之定时任务
    Linux之LVM
    Linux之硬盘与分区
    Linux之文件重定向与查找
    Linux之文件压缩
    Linux之文件权限
    Linux之用户管理
    Linux之文件管理
  • 原文地址:https://www.cnblogs.com/nutix/p/15189748.html
Copyright © 2020-2023  润新知