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(/\breturn\b/) ? 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 的语义化的、直观的形式来编写我们想要的查询逻辑。

 

posted @ 2021-08-26 15:17  nutix  阅读(4109)  评论(0编辑  收藏  举报