JavaScript从特定元素/索引开始迭代Map()

时间:2019-05-23 14:54:44

标签: javascript loops iterator iteration

我知道Map中的元素可以按照插入顺序进行迭代。

假设我们有这张地图:

const a = new Map();
a.set('x', 5);
a.set('y', 10);
a.set('z', 5);

我们想在a中找到第一个元素,值为5,然后在下一个元素中找到相同值的5

// el will be 5, 10, 5...
for(const el of a) {
  if(el === 0) {
    // How can I iteratate over `a` starting from index(el) + 1
    for (??) {}
  }    
}

如果我使用的是Array,我们可以做类似的事情(忽略键):

const a = new Array(5, 10, 5);
for(let i = 0; i < a.length; ++i) {
  if(a[i] === 5) {
    // Here I can start iterating from i + 1
    for(let j = i + 1; j < a.length; ++j) {
         a[j] === 5 && console.log('FOUND!');
    }
  }
}

我对iterators不太熟悉,但是我认为应该可以从地图中的特定元素开始进行迭代。

const x = a.get('x');
 // iterate over Map `a` starting from the element that comes after x

我不特别满意的一种解决方案是,每次执行操作const elements = a.entries()时都获得键或条目的副本,因此我们可以快速对其进行迭代,但是这样做会耗费大量精力额外的内存。

2 个答案:

答案 0 :(得分:2)

您可以使用生成器来执行此操作。.

一个优点是您可以将发电机短路。

下面的例子。

const a = new Map();
a.set('x', 5);
a.set('y', 10);
a.set('z', 5);

a.set('a', 10);
a.set('b', 5);

function* findFirstThenNext(m, v) {
  let ix = 0; 
  for (const mm of m) {
    if (v === mm[1]) {
      yield {ix, key:mm[0]};
    }
    ix += 1;
  }
}

let count = 0;
for (const ret of findFirstThenNext(a, 5)) {
  console.log(`Found @${ret.ix} with key ${ret.key}`);
  count ++;
  if (count >= 2) break;
}

使用for循环和迭代器的混合,您可以创建简单的列表,然后使用迭代器进行两次for循环。

这里的好处是,如果在很多地方使用这种for循环,那么makeOuterInnerIter函数就可以重复用于任何可迭代的地方。

const a = new Map();
a.set('x', 5);
a.set('y', 10);
a.set('z', 5);

function* makeOuterInnerIter(iter) {
  const stack = Array.from(iter);
  for (let ol = 0; ol < stack.length; ol += 1) {
    yield {
      value: stack[ol],
      inner: (function *inner() {
        for (let il = ol + 1; il < stack.length; il += 1) yield stack[il];
      })()
    };
  }
}


for (const {value: [okey, ovalue], inner} of makeOuterInnerIter(a)) {
  console.log(`outer: ${okey}: ${ovalue}`);
  for (const [ikey, ivalue] of inner) {
    console.log(`  inner: ${ikey}: ${ivalue}`);
  }
}

答案 1 :(得分:0)

使用生成器的另一种方法:

function* itWrapper(iterator, value) {
    let found = false;
    for(let item of iterator) {
        if(item[1] == value) {
            if(found) {
                yield 'FOUND!'; // or: yield item[1];
            } else {
                found = true;
            }
        }
    }
}

然后像这样使用:

for(let item of itWrapper(a[Symbol.iterator](), 5)) {
    console.log(item);
}