遍历稀疏数组:跳过undefined并保留原索引的更优实现方案
稀疏数组遍历:跳过undefined且保留原索引
我有如下稀疏数组:
> arr = ["a",,"b"] [ 'a', <1 empty item>, 'b' ]
希望遍历数组时跳过undefined元素,但保留原索引,比如上述数组期望得到[0,"a"]和[2,"b"]。
已尝试的方法
直接遍历entries会包含undefined
> for(let [i,v] of arr.entries()) {console.log(i,v)} 0 a 1 undefined 2 b
forEach自动跳过undefined,但无法配合yield使用
> arr.forEach((v,i)=>console.log(i,v)) 0 a 2 b
但如果需要在循环中使用yield,这种方式行不通——yield不能出现在forEach的回调函数内部。
filter后遍历会丢失原索引
> for(let [i,v] of arr.filter(v=>v!==undefined).entries()) {console.log(i,v)} 0 a 1 b
当前可用但不够简洁的写法
- 手动判断过滤
> for(let [i,v] of arr.entries()) { if(v!==undefined) {console.log(i,v)} } 0 a 2 b
- 先展开entries再过滤
> for(let [i,v] of [...arr.entries()].filter(([i,v])=>v!==undefined)) {console.log(i,v)} 0 a 2 b
数组规模不大,性能不是问题,想问有没有更简洁的实现方式?
背景
该稀疏数组通过以下方式创建:
let arr = []; for(let [i,v] of somecalculations(somedata)) { arr[i] = v; }
索引无限制,可能得到["a","b","c"]、[,,,,,"a"]或[]这类数组。
额外需求:成对迭代
还需要实现连续配对的迭代(比如[1,2],[2,3]这种),当前实现如下:
function *pairwise(arr) { let it = [...arr.entries()].filter(([i,v])=>v!==undefined).values(); let curr = it.next(); let next = it.next(); while(!next.done) { yield [curr.value, next.value]; curr = next; next = it.next(); } }
对于数组["a",,"b","c"],输出为[[0,"a"],[2,"b"]]和[[2,"b"],[3,"c"]];若数组仅含一个元素,则无输出。
消费生成器的方式:
for(let [[i1,v1],[i2,v2]] of pairwise(arr)) { // 处理配对数据 // 聚合结果 } // 后续对结果做进一步计算
简洁实现方案
1. 自定义生成器遍历有效元素
写一个轻量生成器来遍历数组中的有效元素(跳过undefined),既保留原索引,又支持在迭代中使用yield:
function* validEntries(arr) { for (const [i, v] of arr.entries()) { if (v !== undefined) yield [i, v]; } }
使用示例:
for (const [i, v] of validEntries(["a",,"b"])) { console.log(i, v); // 输出:0 a;2 b }
这个写法比手动判断更清晰,也避免了一次性展开所有entries的额外内存占用。
2. 优化成对迭代生成器
基于上面的validEntries生成器,可以简化pairwise逻辑,无需提前把所有条目转成数组:
function* pairwise(arr) { const it = validEntries(arr); let curr = it.next(); if (curr.done) return; // 数组为空或只有一个元素时直接返回 let next = it.next(); while (!next.done) { yield [curr.value, next.value]; curr = next; next = it.next(); } }
测试示例:
for (const pair of pairwise(["a",,"b","c"])) { console.log(pair); // 输出:[[0,"a"],[2,"b"]];[[2,"b"],[3,"c"]] }
3. 利用Object.keys(限整数索引场景)
如果数组的索引都是非负整数,稀疏数组的空元素不会被Object.keys捕获,可以用这种方式:
for (const strIdx of Object.keys(["a",,"b"])) { const idx = parseInt(strIdx, 10); console.log(idx, arr[idx]); // 输出:0 a;2 b }
注意:Object.keys返回的是字符串类型的索引,需要转成数字;如果数组包含负数或非整数索引,这个方法不适用。
内容的提问来源于stack exchange,提问作者Lesmana
相关产品推荐
相关产品推荐

