Index: third_party/google_input_tools/third_party/closure_library/closure/goog/iter/iter.js |
diff --git a/third_party/google_input_tools/third_party/closure_library/closure/goog/iter/iter.js b/third_party/google_input_tools/third_party/closure_library/closure/goog/iter/iter.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b7744d5fbf9b92ba284127663501e6b53abe8750 |
--- /dev/null |
+++ b/third_party/google_input_tools/third_party/closure_library/closure/goog/iter/iter.js |
@@ -0,0 +1,1314 @@ |
+// Copyright 2007 The Closure Library Authors. All Rights Reserved. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS-IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+ |
+/** |
+ * @fileoverview Python style iteration utilities. |
+ * @author arv@google.com (Erik Arvidsson) |
+ */ |
+ |
+ |
+goog.provide('goog.iter'); |
+goog.provide('goog.iter.Iterable'); |
+goog.provide('goog.iter.Iterator'); |
+goog.provide('goog.iter.StopIteration'); |
+ |
+goog.require('goog.array'); |
+goog.require('goog.asserts'); |
+goog.require('goog.functions'); |
+goog.require('goog.math'); |
+ |
+ |
+/** |
+ * @typedef {goog.iter.Iterator|{length:number}|{__iterator__}} |
+ */ |
+goog.iter.Iterable; |
+ |
+ |
+// For script engines that already support iterators. |
+if ('StopIteration' in goog.global) { |
+ /** |
+ * Singleton Error object that is used to terminate iterations. |
+ * @type {Error} |
+ */ |
+ goog.iter.StopIteration = goog.global['StopIteration']; |
+} else { |
+ /** |
+ * Singleton Error object that is used to terminate iterations. |
+ * @type {Error} |
+ * @suppress {duplicate} |
+ */ |
+ goog.iter.StopIteration = Error('StopIteration'); |
+} |
+ |
+ |
+ |
+/** |
+ * Class/interface for iterators. An iterator needs to implement a {@code next} |
+ * method and it needs to throw a {@code goog.iter.StopIteration} when the |
+ * iteration passes beyond the end. Iterators have no {@code hasNext} method. |
+ * It is recommended to always use the helper functions to iterate over the |
+ * iterator or in case you are only targeting JavaScript 1.7 for in loops. |
+ * @constructor |
+ * @template VALUE |
+ */ |
+goog.iter.Iterator = function() {}; |
+ |
+ |
+/** |
+ * Returns the next value of the iteration. This will throw the object |
+ * {@see goog.iter#StopIteration} when the iteration passes the end. |
+ * @return {VALUE} Any object or value. |
+ */ |
+goog.iter.Iterator.prototype.next = function() { |
+ throw goog.iter.StopIteration; |
+}; |
+ |
+ |
+/** |
+ * Returns the {@code Iterator} object itself. This is used to implement |
+ * the iterator protocol in JavaScript 1.7 |
+ * @param {boolean=} opt_keys Whether to return the keys or values. Default is |
+ * to only return the values. This is being used by the for-in loop (true) |
+ * and the for-each-in loop (false). Even though the param gives a hint |
+ * about what the iterator will return there is no guarantee that it will |
+ * return the keys when true is passed. |
+ * @return {!goog.iter.Iterator.<VALUE>} The object itself. |
+ */ |
+goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) { |
+ return this; |
+}; |
+ |
+ |
+/** |
+ * Returns an iterator that knows how to iterate over the values in the object. |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable If the |
+ * object is an iterator it will be returned as is. If the object has an |
+ * {@code __iterator__} method that will be called to get the value |
+ * iterator. If the object is an array-like object we create an iterator |
+ * for that. |
+ * @return {!goog.iter.Iterator.<VALUE>} An iterator that knows how to iterate |
+ * over the values in {@code iterable}. |
+ * @template VALUE |
+ */ |
+goog.iter.toIterator = function(iterable) { |
+ if (iterable instanceof goog.iter.Iterator) { |
+ return iterable; |
+ } |
+ if (typeof iterable.__iterator__ == 'function') { |
+ return iterable.__iterator__(false); |
+ } |
+ if (goog.isArrayLike(iterable)) { |
+ var i = 0; |
+ var newIter = new goog.iter.Iterator; |
+ newIter.next = function() { |
+ while (true) { |
+ if (i >= iterable.length) { |
+ throw goog.iter.StopIteration; |
+ } |
+ // Don't include deleted elements. |
+ if (!(i in iterable)) { |
+ i++; |
+ continue; |
+ } |
+ return iterable[i++]; |
+ } |
+ }; |
+ return newIter; |
+ } |
+ |
+ |
+ // TODO(arv): Should we fall back on goog.structs.getValues()? |
+ throw Error('Not implemented'); |
+}; |
+ |
+ |
+/** |
+ * Calls a function for each element in the iterator with the element of the |
+ * iterator passed as argument. |
+ * |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * to iterate over. If the iterable is an object {@code toIterator} will be |
+ * called on it. |
+ * @param {function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>)| |
+ * function(this:THIS,number,undefined,goog.iter.Iterator.<VALUE>)} f |
+ * The function to call for every element. This function takes 3 arguments |
+ * (the element, undefined, and the iterator) and the return value is |
+ * irrelevant. The reason for passing undefined as the second argument is |
+ * so that the same function can be used in {@see goog.array#forEach} as |
+ * well as others. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.forEach = function(iterable, f, opt_obj) { |
+ if (goog.isArrayLike(iterable)) { |
+ /** @preserveTry */ |
+ try { |
+ // NOTES: this passes the index number to the second parameter |
+ // of the callback contrary to the documentation above. |
+ goog.array.forEach(/** @type {goog.array.ArrayLike} */(iterable), f, |
+ opt_obj); |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ } |
+ } else { |
+ iterable = goog.iter.toIterator(iterable); |
+ /** @preserveTry */ |
+ try { |
+ while (true) { |
+ f.call(opt_obj, iterable.next(), undefined, iterable); |
+ } |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ } |
+ } |
+}; |
+ |
+ |
+/** |
+ * Calls a function for every element in the iterator, and if the function |
+ * returns true adds the element to a new iterator. |
+ * |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * to iterate over. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>):boolean} f |
+ * The function to call for every element. This function takes 3 arguments |
+ * (the element, undefined, and the iterator) and should return a boolean. |
+ * If the return value is true the element will be included in the returned |
+ * iterator. If it is false the element is not included. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator in which only elements |
+ * that passed the test are present. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.filter = function(iterable, f, opt_obj) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var newIter = new goog.iter.Iterator; |
+ newIter.next = function() { |
+ while (true) { |
+ var val = iterator.next(); |
+ if (f.call(opt_obj, val, undefined, iterator)) { |
+ return val; |
+ } |
+ } |
+ }; |
+ return newIter; |
+}; |
+ |
+ |
+/** |
+ * Calls a function for every element in the iterator, and if the function |
+ * returns false adds the element to a new iterator. |
+ * |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * to iterate over. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>):boolean} f |
+ * The function to call for every element. This function takes 3 arguments |
+ * (the element, undefined, and the iterator) and should return a boolean. |
+ * If the return value is false the element will be included in the returned |
+ * iterator. If it is true the element is not included. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator in which only elements |
+ * that did not pass the test are present. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.filterFalse = function(iterable, f, opt_obj) { |
+ return goog.iter.filter(iterable, goog.functions.not(f), opt_obj); |
+}; |
+ |
+ |
+/** |
+ * Creates a new iterator that returns the values in a range. This function |
+ * can take 1, 2 or 3 arguments: |
+ * <pre> |
+ * range(5) same as range(0, 5, 1) |
+ * range(2, 5) same as range(2, 5, 1) |
+ * </pre> |
+ * |
+ * @param {number} startOrStop The stop value if only one argument is provided. |
+ * The start value if 2 or more arguments are provided. If only one |
+ * argument is used the start value is 0. |
+ * @param {number=} opt_stop The stop value. If left out then the first |
+ * argument is used as the stop value. |
+ * @param {number=} opt_step The number to increment with between each call to |
+ * next. This can be negative. |
+ * @return {!goog.iter.Iterator.<number>} A new iterator that returns the values |
+ * in the range. |
+ */ |
+goog.iter.range = function(startOrStop, opt_stop, opt_step) { |
+ var start = 0; |
+ var stop = startOrStop; |
+ var step = opt_step || 1; |
+ if (arguments.length > 1) { |
+ start = startOrStop; |
+ stop = opt_stop; |
+ } |
+ if (step == 0) { |
+ throw Error('Range step argument must not be zero'); |
+ } |
+ |
+ var newIter = new goog.iter.Iterator; |
+ newIter.next = function() { |
+ if (step > 0 && start >= stop || step < 0 && start <= stop) { |
+ throw goog.iter.StopIteration; |
+ } |
+ var rv = start; |
+ start += step; |
+ return rv; |
+ }; |
+ return newIter; |
+}; |
+ |
+ |
+/** |
+ * Joins the values in a iterator with a delimiter. |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * to get the values from. |
+ * @param {string} deliminator The text to put between the values. |
+ * @return {string} The joined value string. |
+ * @template VALUE |
+ */ |
+goog.iter.join = function(iterable, deliminator) { |
+ return goog.iter.toArray(iterable).join(deliminator); |
+}; |
+ |
+ |
+/** |
+ * For every element in the iterator call a function and return a new iterator |
+ * with that value. |
+ * |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterator to iterate over. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator.<VALUE>):RESULT} f |
+ * The function to call for every element. This function takes 3 arguments |
+ * (the element, undefined, and the iterator) and should return a new value. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {!goog.iter.Iterator.<RESULT>} A new iterator that returns the |
+ * results of applying the function to each element in the original |
+ * iterator. |
+ * @template THIS, VALUE, RESULT |
+ */ |
+goog.iter.map = function(iterable, f, opt_obj) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var newIter = new goog.iter.Iterator; |
+ newIter.next = function() { |
+ var val = iterator.next(); |
+ return f.call(opt_obj, val, undefined, iterator); |
+ }; |
+ return newIter; |
+}; |
+ |
+ |
+/** |
+ * Passes every element of an iterator into a function and accumulates the |
+ * result. |
+ * |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * to iterate over. |
+ * @param {function(this:THIS,VALUE,VALUE):VALUE} f The function to call for |
+ * every element. This function takes 2 arguments (the function's previous |
+ * result or the initial value, and the value of the current element). |
+ * function(previousValue, currentElement) : newValue. |
+ * @param {VALUE} val The initial value to pass into the function on the first |
+ * call. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * f. |
+ * @return {VALUE} Result of evaluating f repeatedly across the values of |
+ * the iterator. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.reduce = function(iterable, f, val, opt_obj) { |
+ var rval = val; |
+ goog.iter.forEach(iterable, function(val) { |
+ rval = f.call(opt_obj, rval, val); |
+ }); |
+ return rval; |
+}; |
+ |
+ |
+/** |
+ * Goes through the values in the iterator. Calls f for each of these, and if |
+ * any of them returns true, this returns true (without checking the rest). If |
+ * all return false this will return false. |
+ * |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * object. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>):boolean} f |
+ * The function to call for every value. This function takes 3 arguments |
+ * (the value, undefined, and the iterator) and should return a boolean. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {boolean} true if any value passes the test. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.some = function(iterable, f, opt_obj) { |
+ iterable = goog.iter.toIterator(iterable); |
+ /** @preserveTry */ |
+ try { |
+ while (true) { |
+ if (f.call(opt_obj, iterable.next(), undefined, iterable)) { |
+ return true; |
+ } |
+ } |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ } |
+ return false; |
+}; |
+ |
+ |
+/** |
+ * Goes through the values in the iterator. Calls f for each of these and if any |
+ * of them returns false this returns false (without checking the rest). If all |
+ * return true this will return true. |
+ * |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * object. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>):boolean} f |
+ * The function to call for every value. This function takes 3 arguments |
+ * (the value, undefined, and the iterator) and should return a boolean. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {boolean} true if every value passes the test. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.every = function(iterable, f, opt_obj) { |
+ iterable = goog.iter.toIterator(iterable); |
+ /** @preserveTry */ |
+ try { |
+ while (true) { |
+ if (!f.call(opt_obj, iterable.next(), undefined, iterable)) { |
+ return false; |
+ } |
+ } |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ } |
+ return true; |
+}; |
+ |
+ |
+/** |
+ * Takes zero or more iterables and returns one iterator that will iterate over |
+ * them in the order chained. |
+ * @param {...!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} var_args Any |
+ * number of iterable objects. |
+ * @return {!goog.iter.Iterator.<VALUE>} Returns a new iterator that will |
+ * iterate over all the given iterables' contents. |
+ * @template VALUE |
+ */ |
+goog.iter.chain = function(var_args) { |
+ var iterator = goog.iter.toIterator(arguments); |
+ var iter = new goog.iter.Iterator(); |
+ var current = null; |
+ |
+ iter.next = function() { |
+ while (true) { |
+ if (current == null) { |
+ var it = iterator.next(); |
+ current = goog.iter.toIterator(it); |
+ } |
+ try { |
+ return current.next(); |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ current = null; |
+ } |
+ } |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Takes a single iterable containing zero or more iterables and returns one |
+ * iterator that will iterate over each one in the order given. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.chain.from_iterable |
+ * @param {goog.iter.Iterable} iterable The iterable of iterables to chain. |
+ * @return {!goog.iter.Iterator.<VALUE>} Returns a new iterator that will |
+ * iterate over all the contents of the iterables contained within |
+ * {@code iterable}. |
+ * @template VALUE |
+ */ |
+goog.iter.chainFromIterable = function(iterable) { |
+ return goog.iter.chain.apply(undefined, iterable); |
+}; |
+ |
+ |
+/** |
+ * Builds a new iterator that iterates over the original, but skips elements as |
+ * long as a supplied function returns true. |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * object. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>):boolean} f |
+ * The function to call for every value. This function takes 3 arguments |
+ * (the value, undefined, and the iterator) and should return a boolean. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator that drops elements from |
+ * the original iterator as long as {@code f} is true. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.dropWhile = function(iterable, f, opt_obj) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var newIter = new goog.iter.Iterator; |
+ var dropping = true; |
+ newIter.next = function() { |
+ while (true) { |
+ var val = iterator.next(); |
+ if (dropping && f.call(opt_obj, val, undefined, iterator)) { |
+ continue; |
+ } else { |
+ dropping = false; |
+ } |
+ return val; |
+ } |
+ }; |
+ return newIter; |
+}; |
+ |
+ |
+/** |
+ * Builds a new iterator that iterates over the original, but only as long as a |
+ * supplied function returns true. |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * object. |
+ * @param { |
+ * function(this:THIS,VALUE,undefined,goog.iter.Iterator.<VALUE>):boolean} f |
+ * The function to call for every value. This function takes 3 arguments |
+ * (the value, undefined, and the iterator) and should return a boolean. |
+ * @param {THIS=} opt_obj This is used as the 'this' object in f when called. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator that keeps elements in |
+ * the original iterator as long as the function is true. |
+ * @template THIS, VALUE |
+ */ |
+goog.iter.takeWhile = function(iterable, f, opt_obj) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var newIter = new goog.iter.Iterator; |
+ var taking = true; |
+ newIter.next = function() { |
+ while (true) { |
+ if (taking) { |
+ var val = iterator.next(); |
+ if (f.call(opt_obj, val, undefined, iterator)) { |
+ return val; |
+ } else { |
+ taking = false; |
+ } |
+ } else { |
+ throw goog.iter.StopIteration; |
+ } |
+ } |
+ }; |
+ return newIter; |
+}; |
+ |
+ |
+/** |
+ * Converts the iterator to an array |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterator |
+ * to convert to an array. |
+ * @return {!Array.<VALUE>} An array of the elements the iterator iterates over. |
+ * @template VALUE |
+ */ |
+goog.iter.toArray = function(iterable) { |
+ // Fast path for array-like. |
+ if (goog.isArrayLike(iterable)) { |
+ return goog.array.toArray(/** @type {!goog.array.ArrayLike} */(iterable)); |
+ } |
+ iterable = goog.iter.toIterator(iterable); |
+ var array = []; |
+ goog.iter.forEach(iterable, function(val) { |
+ array.push(val); |
+ }); |
+ return array; |
+}; |
+ |
+ |
+/** |
+ * Iterates over two iterables and returns true if they contain the same |
+ * sequence of elements and have the same length. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable1 The first |
+ * iterable object. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable2 The second |
+ * iterable object. |
+ * @return {boolean} true if the iterables contain the same sequence of elements |
+ * and have the same length. |
+ * @template VALUE |
+ */ |
+goog.iter.equals = function(iterable1, iterable2) { |
+ var fillValue = {}; |
+ var pairs = goog.iter.zipLongest(fillValue, iterable1, iterable2); |
+ return goog.iter.every(pairs, function(pair) { |
+ return pair[0] == pair[1]; |
+ }); |
+}; |
+ |
+ |
+/** |
+ * Advances the iterator to the next position, returning the given default value |
+ * instead of throwing an exception if the iterator has no more entries. |
+ * @param {goog.iter.Iterator.<VALUE>|goog.iter.Iterable} iterable The iterable |
+ * object. |
+ * @param {VALUE} defaultValue The value to return if the iterator is empty. |
+ * @return {VALUE} The next item in the iteration, or defaultValue if the |
+ * iterator was empty. |
+ * @template VALUE |
+ */ |
+goog.iter.nextOrValue = function(iterable, defaultValue) { |
+ try { |
+ return goog.iter.toIterator(iterable).next(); |
+ } catch (e) { |
+ if (e != goog.iter.StopIteration) { |
+ throw e; |
+ } |
+ return defaultValue; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Cartesian product of zero or more sets. Gives an iterator that gives every |
+ * combination of one element chosen from each set. For example, |
+ * ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]). |
+ * @see http://docs.python.org/library/itertools.html#itertools.product |
+ * @param {...!goog.array.ArrayLike.<VALUE>} var_args Zero or more sets, as |
+ * arrays. |
+ * @return {!goog.iter.Iterator.<!Array.<VALUE>>} An iterator that gives each |
+ * n-tuple (as an array). |
+ * @template VALUE |
+ */ |
+goog.iter.product = function(var_args) { |
+ var someArrayEmpty = goog.array.some(arguments, function(arr) { |
+ return !arr.length; |
+ }); |
+ |
+ // An empty set in a cartesian product gives an empty set. |
+ if (someArrayEmpty || !arguments.length) { |
+ return new goog.iter.Iterator(); |
+ } |
+ |
+ var iter = new goog.iter.Iterator(); |
+ var arrays = arguments; |
+ |
+ // The first indices are [0, 0, ...] |
+ var indicies = goog.array.repeat(0, arrays.length); |
+ |
+ iter.next = function() { |
+ |
+ if (indicies) { |
+ var retVal = goog.array.map(indicies, function(valueIndex, arrayIndex) { |
+ return arrays[arrayIndex][valueIndex]; |
+ }); |
+ |
+ // Generate the next-largest indices for the next call. |
+ // Increase the rightmost index. If it goes over, increase the next |
+ // rightmost (like carry-over addition). |
+ for (var i = indicies.length - 1; i >= 0; i--) { |
+ // Assertion prevents compiler warning below. |
+ goog.asserts.assert(indicies); |
+ if (indicies[i] < arrays[i].length - 1) { |
+ indicies[i]++; |
+ break; |
+ } |
+ |
+ // We're at the last indices (the last element of every array), so |
+ // the iteration is over on the next call. |
+ if (i == 0) { |
+ indicies = null; |
+ break; |
+ } |
+ // Reset the index in this column and loop back to increment the |
+ // next one. |
+ indicies[i] = 0; |
+ } |
+ return retVal; |
+ } |
+ |
+ throw goog.iter.StopIteration; |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Create an iterator to cycle over the iterable's elements indefinitely. |
+ * For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ... |
+ * @see: http://docs.python.org/library/itertools.html#itertools.cycle. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable object. |
+ * @return {!goog.iter.Iterator.<VALUE>} An iterator that iterates indefinitely |
+ * over the values in {@code iterable}. |
+ * @template VALUE |
+ */ |
+goog.iter.cycle = function(iterable) { |
+ var baseIterator = goog.iter.toIterator(iterable); |
+ |
+ // We maintain a cache to store the iterable elements as we iterate |
+ // over them. The cache is used to return elements once we have |
+ // iterated over the iterable once. |
+ var cache = []; |
+ var cacheIndex = 0; |
+ |
+ var iter = new goog.iter.Iterator(); |
+ |
+ // This flag is set after the iterable is iterated over once |
+ var useCache = false; |
+ |
+ iter.next = function() { |
+ var returnElement = null; |
+ |
+ // Pull elements off the original iterator if not using cache |
+ if (!useCache) { |
+ try { |
+ // Return the element from the iterable |
+ returnElement = baseIterator.next(); |
+ cache.push(returnElement); |
+ return returnElement; |
+ } catch (e) { |
+ // If an exception other than StopIteration is thrown |
+ // or if there are no elements to iterate over (the iterable was empty) |
+ // throw an exception |
+ if (e != goog.iter.StopIteration || goog.array.isEmpty(cache)) { |
+ throw e; |
+ } |
+ // set useCache to true after we know that a 'StopIteration' exception |
+ // was thrown and the cache is not empty (to handle the 'empty iterable' |
+ // use case) |
+ useCache = true; |
+ } |
+ } |
+ |
+ returnElement = cache[cacheIndex]; |
+ cacheIndex = (cacheIndex + 1) % cache.length; |
+ |
+ return returnElement; |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that counts indefinitely from a starting value. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.count |
+ * @param {number=} opt_start The starting value. Default is 0. |
+ * @param {number=} opt_step The number to increment with between each call to |
+ * next. Negative and floating point numbers are allowed. Default is 1. |
+ * @return {!goog.iter.Iterator.<number>} A new iterator that returns the values |
+ * in the series. |
+ */ |
+goog.iter.count = function(opt_start, opt_step) { |
+ var counter = opt_start || 0; |
+ var step = goog.isDef(opt_step) ? opt_step : 1; |
+ var iter = new goog.iter.Iterator(); |
+ |
+ iter.next = function() { |
+ var returnValue = counter; |
+ counter += step; |
+ return returnValue; |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns the same object or value repeatedly. |
+ * @param {VALUE} value Any object or value to repeat. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator that returns the |
+ * repeated value. |
+ * @template VALUE |
+ */ |
+goog.iter.repeat = function(value) { |
+ var iter = new goog.iter.Iterator(); |
+ |
+ iter.next = goog.functions.constant(value); |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns running totals from the numbers in |
+ * {@code iterable}. For example, the array {@code [1, 2, 3, 4, 5]} yields |
+ * {@code 1 -> 3 -> 6 -> 10 -> 15}. |
+ * @see http://docs.python.org/3.2/library/itertools.html#itertools.accumulate |
+ * @param {!goog.iter.Iterable.<number>} iterable The iterable of numbers to |
+ * accumulate. |
+ * @return {!goog.iter.Iterator.<number>} A new iterator that returns the |
+ * numbers in the series. |
+ */ |
+goog.iter.accumulate = function(iterable) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var total = 0; |
+ var iter = new goog.iter.Iterator(); |
+ |
+ iter.next = function() { |
+ total += iterator.next(); |
+ return total; |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns arrays containing the ith elements from the |
+ * provided iterables. The returned arrays will be the same size as the number |
+ * of iterables given in {@code var_args}. Once the shortest iterable is |
+ * exhausted, subsequent calls to {@code next()} will throw |
+ * {@code goog.iter.StopIteration}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.izip |
+ * @param {...!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} var_args Any |
+ * number of iterable objects. |
+ * @return {!goog.iter.Iterator.<!Array.<VALUE>>} A new iterator that returns |
+ * arrays of elements from the provided iterables. |
+ * @template VALUE |
+ */ |
+goog.iter.zip = function(var_args) { |
+ var args = arguments; |
+ var iter = new goog.iter.Iterator(); |
+ |
+ if (args.length > 0) { |
+ var iterators = goog.array.map(args, goog.iter.toIterator); |
+ iter.next = function() { |
+ var arr = goog.array.map(iterators, function(it) { |
+ return it.next(); |
+ }); |
+ return arr; |
+ }; |
+ } |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns arrays containing the ith elements from the |
+ * provided iterables. The returned arrays will be the same size as the number |
+ * of iterables given in {@code var_args}. Shorter iterables will be extended |
+ * with {@code fillValue}. Once the longest iterable is exhausted, subsequent |
+ * calls to {@code next()} will throw {@code goog.iter.StopIteration}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.izip_longest |
+ * @param {VALUE} fillValue The object or value used to fill shorter iterables. |
+ * @param {...!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} var_args Any |
+ * number of iterable objects. |
+ * @return {!goog.iter.Iterator.<!Array.<VALUE>>} A new iterator that returns |
+ * arrays of elements from the provided iterables. |
+ * @template VALUE |
+ */ |
+goog.iter.zipLongest = function(fillValue, var_args) { |
+ var args = goog.array.slice(arguments, 1); |
+ var iter = new goog.iter.Iterator(); |
+ |
+ if (args.length > 0) { |
+ var iterators = goog.array.map(args, goog.iter.toIterator); |
+ |
+ iter.next = function() { |
+ var iteratorsHaveValues = false; // false when all iterators are empty. |
+ var arr = goog.array.map(iterators, function(it) { |
+ var returnValue; |
+ try { |
+ returnValue = it.next(); |
+ // Iterator had a value, so we've not exhausted the iterators. |
+ // Set flag accordingly. |
+ iteratorsHaveValues = true; |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ returnValue = fillValue; |
+ } |
+ return returnValue; |
+ }); |
+ |
+ if (!iteratorsHaveValues) { |
+ throw goog.iter.StopIteration; |
+ } |
+ return arr; |
+ }; |
+ } |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that filters {@code iterable} based on a series of |
+ * {@code selectors}. On each call to {@code next()}, one item is taken from |
+ * both the {@code iterable} and {@code selectors} iterators. If the item from |
+ * {@code selectors} evaluates to true, the item from {@code iterable} is given. |
+ * Otherwise, it is skipped. Once either {@code iterable} or {@code selectors} |
+ * is exhausted, subsequent calls to {@code next()} will throw |
+ * {@code goog.iter.StopIteration}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.compress |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to filter. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} selectors An |
+ * iterable of items to be evaluated in a boolean context to determine if |
+ * the corresponding element in {@code iterable} should be included in the |
+ * result. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator that returns the |
+ * filtered values. |
+ * @template VALUE |
+ */ |
+goog.iter.compress = function(iterable, selectors) { |
+ var selectorIterator = goog.iter.toIterator(selectors); |
+ |
+ return goog.iter.filter(iterable, function() { |
+ return !!selectorIterator.next(); |
+ }); |
+}; |
+ |
+ |
+ |
+/** |
+ * Implements the {@code goog.iter.groupBy} iterator. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to group. |
+ * @param {function(...[VALUE]): KEY=} opt_keyFunc Optional function for |
+ * determining the key value for each group in the {@code iterable}. Default |
+ * is the identity function. |
+ * @constructor |
+ * @extends {goog.iter.Iterator.<!Array>} |
+ * @template KEY, VALUE |
+ * @private |
+ */ |
+goog.iter.GroupByIterator_ = function(iterable, opt_keyFunc) { |
+ |
+ /** |
+ * The iterable to group, coerced to an iterator. |
+ * @type {!goog.iter.Iterator} |
+ */ |
+ this.iterator = goog.iter.toIterator(iterable); |
+ |
+ /** |
+ * A function for determining the key value for each element in the iterable. |
+ * If no function is provided, the identity function is used and returns the |
+ * element unchanged. |
+ * @type {function(...[VALUE]): KEY} |
+ */ |
+ this.keyFunc = opt_keyFunc || goog.functions.identity; |
+ |
+ /** |
+ * The target key for determining the start of a group. |
+ * @type {KEY} |
+ */ |
+ this.targetKey; |
+ |
+ /** |
+ * The current key visited during iteration. |
+ * @type {KEY} |
+ */ |
+ this.currentKey; |
+ |
+ /** |
+ * The current value being added to the group. |
+ * @type {VALUE} |
+ */ |
+ this.currentValue; |
+}; |
+goog.inherits(goog.iter.GroupByIterator_, goog.iter.Iterator); |
+ |
+ |
+/** @override */ |
+goog.iter.GroupByIterator_.prototype.next = function() { |
+ while (this.currentKey == this.targetKey) { |
+ this.currentValue = this.iterator.next(); // Exits on StopIteration |
+ this.currentKey = this.keyFunc(this.currentValue); |
+ } |
+ this.targetKey = this.currentKey; |
+ return [this.currentKey, this.groupItems_(this.targetKey)]; |
+}; |
+ |
+ |
+/** |
+ * Performs the grouping of objects using the given key. |
+ * @param {KEY} targetKey The target key object for the group. |
+ * @return {!Array.<VALUE>} An array of grouped objects. |
+ * @private |
+ */ |
+goog.iter.GroupByIterator_.prototype.groupItems_ = function(targetKey) { |
+ var arr = []; |
+ while (this.currentKey == targetKey) { |
+ arr.push(this.currentValue); |
+ try { |
+ this.currentValue = this.iterator.next(); |
+ } catch (ex) { |
+ if (ex !== goog.iter.StopIteration) { |
+ throw ex; |
+ } |
+ break; |
+ } |
+ this.currentKey = this.keyFunc(this.currentValue); |
+ } |
+ return arr; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns arrays containing elements from the |
+ * {@code iterable} grouped by a key value. For iterables with repeated |
+ * elements (i.e. sorted according to a particular key function), this function |
+ * has a {@code uniq}-like effect. For example, grouping the array: |
+ * {@code [A, B, B, C, C, A]} produces |
+ * {@code [A, [A]], [B, [B, B]], [C, [C, C]], [A, [A]]}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.groupby |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to group. |
+ * @param {function(...[VALUE]): KEY=} opt_keyFunc Optional function for |
+ * determining the key value for each group in the {@code iterable}. Default |
+ * is the identity function. |
+ * @return {!goog.iter.Iterator.<!Array>} A new iterator that returns arrays of |
+ * consecutive key and groups. |
+ * @template KEY, VALUE |
+ */ |
+goog.iter.groupBy = function(iterable, opt_keyFunc) { |
+ return new goog.iter.GroupByIterator_(iterable, opt_keyFunc); |
+}; |
+ |
+ |
+/** |
+ * Gives an iterator that gives the result of calling the given function |
+ * <code>f</code> with the arguments taken from the next element from |
+ * <code>iterable</code> (the elements are expected to also be iterables). |
+ * |
+ * Similar to {@see goog.iter#map} but allows the function to accept multiple |
+ * arguments from the iterable. |
+ * |
+ * @param {!goog.iter.Iterable.<!goog.iter.Iterable>} iterable The iterable of |
+ * iterables to iterate over. |
+ * @param {function(this:THIS,...[*]):RESULT} f The function to call for every |
+ * element. This function takes N+2 arguments, where N represents the |
+ * number of items from the next element of the iterable. The two |
+ * additional arguments passed to the function are undefined and the |
+ * iterator itself. The function should return a new value. |
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within |
+ * {@code f}. |
+ * @return {!goog.iter.Iterator.<RESULT>} A new iterator that returns the |
+ * results of applying the function to each element in the original |
+ * iterator. |
+ * @template THIS, RESULT |
+ */ |
+goog.iter.starMap = function(iterable, f, opt_obj) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var iter = new goog.iter.Iterator(); |
+ |
+ iter.next = function() { |
+ var args = goog.iter.toArray(iterator.next()); |
+ return f.apply(opt_obj, goog.array.concat(args, undefined, iterator)); |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Returns an array of iterators each of which can iterate over the values in |
+ * {@code iterable} without advancing the others. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.tee |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to tee. |
+ * @param {number=} opt_num The number of iterators to create. Default is 2. |
+ * @return {!Array.<goog.iter.Iterator.<VALUE>>} An array of iterators. |
+ * @template VALUE |
+ */ |
+goog.iter.tee = function(iterable, opt_num) { |
+ var iterator = goog.iter.toIterator(iterable); |
+ var num = goog.isNumber(opt_num) ? opt_num : 2; |
+ var buffers = goog.array.map(goog.array.range(num), function() { |
+ return []; |
+ }); |
+ |
+ var addNextIteratorValueToBuffers = function() { |
+ var val = iterator.next(); |
+ goog.array.forEach(buffers, function(buffer) { |
+ buffer.push(val); |
+ }); |
+ }; |
+ |
+ var createIterator = function(buffer) { |
+ // Each tee'd iterator has an associated buffer (initially empty). When a |
+ // tee'd iterator's buffer is empty, it calls |
+ // addNextIteratorValueToBuffers(), adding the next value to all tee'd |
+ // iterators' buffers, and then returns that value. This allows each |
+ // iterator to be advanced independently. |
+ var iter = new goog.iter.Iterator(); |
+ |
+ iter.next = function() { |
+ if (goog.array.isEmpty(buffer)) { |
+ addNextIteratorValueToBuffers(); |
+ } |
+ goog.asserts.assert(!goog.array.isEmpty(buffer)); |
+ return buffer.shift(); |
+ }; |
+ |
+ return iter; |
+ }; |
+ |
+ return goog.array.map(buffers, createIterator); |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns arrays containing a count and an element |
+ * obtained from the given {@code iterable}. |
+ * @see http://docs.python.org/2/library/functions.html#enumerate |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to enumerate. |
+ * @param {number=} opt_start Optional starting value. Default is 0. |
+ * @return {!goog.iter.Iterator.<!Array>} A new iterator containing count/item |
+ * pairs. |
+ * @template VALUE |
+ */ |
+goog.iter.enumerate = function(iterable, opt_start) { |
+ return goog.iter.zip(goog.iter.count(opt_start), iterable); |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns the first {@code limitSize} elements from an |
+ * iterable. If this number is greater than the number of elements in the |
+ * iterable, all the elements are returned. |
+ * @see http://goo.gl/V0sihp Inspired by the limit iterator in Guava. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to limit. |
+ * @param {number} limitSize The maximum number of elements to return. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator containing |
+ * {@code limitSize} elements. |
+ * @template VALUE |
+ */ |
+goog.iter.limit = function(iterable, limitSize) { |
+ goog.asserts.assert(goog.math.isInt(limitSize) && limitSize >= 0); |
+ |
+ var iterator = goog.iter.toIterator(iterable); |
+ |
+ var iter = new goog.iter.Iterator(); |
+ var remaining = limitSize; |
+ |
+ iter.next = function() { |
+ if (remaining-- > 0) { |
+ return iterator.next(); |
+ } |
+ throw goog.iter.StopIteration; |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that is advanced {@code count} steps ahead. Consumed |
+ * values are silently discarded. If {@code count} is greater than the number |
+ * of elements in {@code iterable}, an empty iterator is returned. Subsequent |
+ * calls to {@code next()} will throw {@code goog.iter.StopIteration}. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to consume. |
+ * @param {number} count The number of elements to consume from the iterator. |
+ * @return {!goog.iter.Iterator.<VALUE>} An iterator advanced zero or more steps |
+ * ahead. |
+ * @template VALUE |
+ */ |
+goog.iter.consume = function(iterable, count) { |
+ goog.asserts.assert(goog.math.isInt(count) && count >= 0); |
+ |
+ var iterator = goog.iter.toIterator(iterable); |
+ |
+ while (count-- > 0) { |
+ goog.iter.nextOrValue(iterator, null); |
+ } |
+ |
+ return iterator; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns a range of elements from an iterable. |
+ * Similar to {@see goog.array#slice} but does not support negative indexes. |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to slice. |
+ * @param {number} start The index of the first element to return. |
+ * @param {number=} opt_end The index after the last element to return. If |
+ * defined, must be greater than or equal to {@code start}. |
+ * @return {!goog.iter.Iterator.<VALUE>} A new iterator containing a slice of |
+ * the original. |
+ * @template VALUE |
+ */ |
+goog.iter.slice = function(iterable, start, opt_end) { |
+ goog.asserts.assert(goog.math.isInt(start) && start >= 0); |
+ |
+ var iterator = goog.iter.consume(iterable, start); |
+ |
+ if (goog.isNumber(opt_end)) { |
+ goog.asserts.assert( |
+ goog.math.isInt(/** @type {number} */ (opt_end)) && opt_end >= start); |
+ iterator = goog.iter.limit(iterator, opt_end - start /* limitSize */); |
+ } |
+ |
+ return iterator; |
+}; |
+ |
+ |
+/** |
+ * Checks an array for duplicate elements. |
+ * @param {Array.<VALUE>|goog.array.ArrayLike} arr The array to check for |
+ * duplicates. |
+ * @return {boolean} True, if the array contains duplicates, false otherwise. |
+ * @private |
+ * @template VALUE |
+ */ |
+// TODO(user): Consider moving this into goog.array as a public function. |
+goog.iter.hasDuplicates_ = function(arr) { |
+ var deduped = []; |
+ goog.array.removeDuplicates(arr, deduped); |
+ return arr.length != deduped.length; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns permutations of elements in |
+ * {@code iterable}. |
+ * |
+ * Permutations are obtained by taking the Cartesian product of |
+ * {@code opt_length} iterables and filtering out those with repeated |
+ * elements. For example, the permutations of {@code [1,2,3]} are |
+ * {@code [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.permutations |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable from which to generate permutations. |
+ * @param {number=} opt_length Length of each permutation. If omitted, defaults |
+ * to the length of {@code iterable}. |
+ * @return {!goog.iter.Iterator.<!Array.<VALUE>>} A new iterator containing the |
+ * permutations of {@code iterable}. |
+ * @template VALUE |
+ */ |
+goog.iter.permutations = function(iterable, opt_length) { |
+ var elements = goog.iter.toArray(iterable); |
+ var length = goog.isNumber(opt_length) ? opt_length : elements.length; |
+ |
+ var sets = goog.array.repeat(elements, length); |
+ var product = goog.iter.product.apply(undefined, sets); |
+ |
+ return goog.iter.filter(product, function(arr) { |
+ return !goog.iter.hasDuplicates_(arr); |
+ }); |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns combinations of elements from |
+ * {@code iterable}. |
+ * |
+ * Combinations are obtained by taking the {@see goog.iter#permutations} of |
+ * {@code iterable} and filtering those whose elements appear in the order they |
+ * are encountered in {@code iterable}. For example, the 3-length combinations |
+ * of {@code [0,1,2,3]} are {@code [[0,1,2], [0,1,3], [0,2,3], [1,2,3]]}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.combinations |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable from which to generate combinations. |
+ * @param {number} length The length of each combination. |
+ * @return {!goog.iter.Iterator.<!Array.<VALUE>>} A new iterator containing |
+ * combinations from the {@code iterable}. |
+ * @template VALUE |
+ */ |
+goog.iter.combinations = function(iterable, length) { |
+ var elements = goog.iter.toArray(iterable); |
+ var indexes = goog.iter.range(elements.length); |
+ var indexIterator = goog.iter.permutations(indexes, length); |
+ // sortedIndexIterator will now give arrays of with the given length that |
+ // indicate what indexes into "elements" should be returned on each iteration. |
+ var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { |
+ return goog.array.isSorted(arr); |
+ }); |
+ |
+ var iter = new goog.iter.Iterator(); |
+ |
+ function getIndexFromElements(index) { |
+ return elements[index]; |
+ } |
+ |
+ iter.next = function() { |
+ return goog.array.map( |
+ /** @type {!Array.<number>} */ |
+ (sortedIndexIterator.next()), getIndexFromElements); |
+ }; |
+ |
+ return iter; |
+}; |
+ |
+ |
+/** |
+ * Creates an iterator that returns combinations of elements from |
+ * {@code iterable}, with repeated elements possible. |
+ * |
+ * Combinations are obtained by taking the Cartesian product of {@code length} |
+ * iterables and filtering those whose elements appear in the order they are |
+ * encountered in {@code iterable}. For example, the 2-length combinations of |
+ * {@code [1,2,3]} are {@code [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]}. |
+ * @see http://docs.python.org/2/library/itertools.html#itertools.combinations_with_replacement |
+ * @see http://en.wikipedia.org/wiki/Combination#Number_of_combinations_with_repetition |
+ * @param {!goog.iter.Iterator.<VALUE>|!goog.iter.Iterable} iterable The |
+ * iterable to combine. |
+ * @param {number} length The length of each combination. |
+ * @return {!goog.iter.Iterator.<!Array.<VALUE>>} A new iterator containing |
+ * combinations from the {@code iterable}. |
+ * @template VALUE |
+ */ |
+goog.iter.combinationsWithReplacement = function(iterable, length) { |
+ var elements = goog.iter.toArray(iterable); |
+ var indexes = goog.array.range(elements.length); |
+ var sets = goog.array.repeat(indexes, length); |
+ var indexIterator = goog.iter.product.apply(undefined, sets); |
+ // sortedIndexIterator will now give arrays of with the given length that |
+ // indicate what indexes into "elements" should be returned on each iteration. |
+ var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { |
+ return goog.array.isSorted(arr); |
+ }); |
+ |
+ var iter = new goog.iter.Iterator(); |
+ |
+ function getIndexFromElements(index) { |
+ return elements[index]; |
+ } |
+ |
+ iter.next = function() { |
+ return goog.array.map( |
+ /** @type {!Array.<number>} */ |
+ (sortedIndexIterator.next()), getIndexFromElements); |
+ }; |
+ |
+ return iter; |
+}; |