我有 2 个暗淡数组,如下所示:
var a = [[1,2,3],[4,5,6],[7,8,9]];
我想编写一个迭代器,它在被调用时一次返回一个值。
iterator(); //returns 1
iterator(); //returns 2
iterator(); //returns 3
我尝试过这样的方法:
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]];
var i, j;
return function() {
for (var i = 0; i < a.length; i++) {
var b = a[i];
for (var j = 0; j < b.length; j++) {
return a[i][j];
}
}
}
};
var a = iterator();
a(); //1
a(); //1
a(); //1
它总是返回第一个元素。
我可以试试这个:
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]];
var i = 0, j = 0;
return function() {
for (; i < a.length; i++) {
var b = a[i];
for (; j < b.length; j++) {
return a[i][j];
}
}
}
};
也不起作用。
但是如果我尝试这个:
function test() {
var a = [1,2,3,4,5], i = 0;
return function() {
while (i < a.length) {
return a[i++];
}
}
}
var a = test();
a(); //1
a(); //2
a(); //3
效果很好。
这里有什么区别?如何让for循环工作?
对我来说另一个明显的问题是界限。当到达数组边界时我应该如何停止?
您可以使用简单的
if
来测试 j
的边界,而不是对第二个维度使用内部 for 循环
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]];
var i = 0, j = 0;
return function() {
for (; i < a.length; i++) {
var b = a[i];
if (j < b.length){
return a[i][j++];
}
j = 0;
}
return undefined; // reached when there is no value left
}
};
为什么在这种情况下你需要一个循环。无论如何,你都在有效地展平数组。您可以只增加索引并进行边界检查:
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]], i = 0, j = 0;
return function() {
if (j >= a[i].length) { j = 0; i++; }
if (i >= a.length) { j = 0; i = 0; }
snippet.log( a[i][j++] );
}
};
var x = iterator();
x(); x(); x(); x(); x(); x(); x(); x(); x(); x();
x(); x(); x(); x(); x(); x(); x(); x(); x(); x();
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
扩展标准功能通常不是一个好主意,但对于教学示例我会例外。为了真正使用,我建议实现你自己的类。
总体思路
Array.prototype.beginIterator = function()
{
var counter = 0;
return function()
{
if (counter<=this.length) return this[counter++];
else return undefined;
};
}
然后你可以像下面这样迭代:
var a = [3,1,4,1,5];
var it = a.beginIterator();
for (var i=it(); i!=undefined; i=it())
{
alert(i);
}
目前仅适用于一维数组,但它可以与任何逻辑一起应用于其他数组或对象。
多维(任意)解决方案:
以下迭代器允许任意组合的任意维度数组:
Array.prototype.beginIterator = function()
{
var counter = 0;
var iterators = null;
return function()
{
val = undefined;
if (iterators!=null)
{
val = iterators();
if (val!==undefined) return val;
else
{
iterators = null;
counter++;
}
}
while (counter <=this.length)
{
if (!(this[counter] instanceof Array)) return this[counter++];
else
{
iterators = this[counter++].beginIterator();
val = iterators();
if (val!==undefined) return val;
}
}
return undefiend;
};
}
使用示例:
var a = [3,[3,5,7],4,[1,[2,5,8]],5];
var it = a.beginIterator();
for (var i=it(); i!=undefined; i=it())
{
alert(i);
}
迭代器实现特定的协议。要使其在具有兼容迭代器的 2D 数组上工作,您可以使用 ECMAScript 2025 中引入的迭代器辅助方法 flatMap (不要与具有相同名称的数组方法混淆):
const a = [[1,2,3],[4,5,6],[7,8,9]];
const it = a.values().flatMap(Object);
console.log(it.next().value); // 1
console.log(it.next().value); // 2
console.log(it.next().value); // 3
console.log(it.next().value); // 4
Object
作为参数传递只是为了获得恒等映射。也可以是x => x
。该回调的目标是返回一个可迭代对象。由于嵌套数组是可迭代的,我们可以按原样返回它。