JavaScript начинает итерацию Map () с определенного элемента / индекса - PullRequest
2 голосов
/ 23 мая 2019

Я знаю, что элементы в 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 ]

2 голосов
/ 23 мая 2019

Для этого можно использовать генераторы, ..

Одним из преимуществ является то, что вы можете замыкать генераторы с разрывом.

Пример ниже ..

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 с помощью итераторов.

Хорошая вещь здесь, если вы используете этот тип для циклического перебора во многих местах, то функция 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}`);
  }
}
0 голосов
/ 23 мая 2019

Еще один подход с генераторами:

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);
}
...