te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>How to peek at the next value in a Javascript Iterator - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to peek at the next value in a Javascript Iterator - Stack Overflow

programmeradmin3浏览0评论

Let's say I have an iterator:

function* someIterator () {
    yield 1;
    yield 2;
    yield 3;
}

let iter = someIterator();

... that I look at the next element to be iterated:

let next = iter.next(); // {value: 1, done: false}

... and I then use the iterator in a loop:

for(let i of iterator)
    console.log(i); 
// 2
// 3

The loop will not include the element looked at. I wish to see the next element while not taking it out of the iteration series.

In other words, I wish to implement:

let next = peek(iter); // {value: 1, done: false}, or alternatively just 1

for(let i of iterator)
    console.log(i); 
// 1
// 2
// 3 

... and I wan't to do it without modifying the code for the iterable function.

What I've tried is in my answer. It works (which is why I made it an answer), but I worry that it builds an object that is more plex than it has to be. And I worry that it will not work for cases where the 'done' object is something different than { value = undefined, done = true }. So any improved answers are very much wele.

Let's say I have an iterator:

function* someIterator () {
    yield 1;
    yield 2;
    yield 3;
}

let iter = someIterator();

... that I look at the next element to be iterated:

let next = iter.next(); // {value: 1, done: false}

... and I then use the iterator in a loop:

for(let i of iterator)
    console.log(i); 
// 2
// 3

The loop will not include the element looked at. I wish to see the next element while not taking it out of the iteration series.

In other words, I wish to implement:

let next = peek(iter); // {value: 1, done: false}, or alternatively just 1

for(let i of iterator)
    console.log(i); 
// 1
// 2
// 3 

... and I wan't to do it without modifying the code for the iterable function.

What I've tried is in my answer. It works (which is why I made it an answer), but I worry that it builds an object that is more plex than it has to be. And I worry that it will not work for cases where the 'done' object is something different than { value = undefined, done = true }. So any improved answers are very much wele.

Share Improve this question edited Apr 11, 2020 at 22:03 pwilcox asked Apr 11, 2020 at 21:58 pwilcoxpwilcox 5,7631 gold badge22 silver badges34 bronze badges 2
  • Do you consider an option of implementing a custom extended iterator or you need a solution that works with native iterators? – Shlang Commented Apr 11, 2020 at 23:10
  • If a native iterator can be wrapped or fed into the extended iterator, and if you don't have to iterate it to make that happen, then yes, I would consider it. – pwilcox Commented Apr 12, 2020 at 0:32
Add a ment  | 

5 Answers 5

Reset to default 6

Just a bit different idea is to use wrapper that makes an iterator kind of eagier.

function peekable(iterator) {
  let state = iterator.next();

  const _i = (function* (initial) {
    while (!state.done) {
      const current = state.value;
      state = iterator.next();
      const arg = yield current;
    }
    return state.value;
  })()

  _i.peek = () => state;
  return _i;
}

function* someIterator () { yield 1; yield 2; yield 3; }
let iter = peekable(someIterator());

let v = iter.peek();
let peeked = iter.peek();
console.log(peeked.value);

for (let i of iter) {
  console.log(i);
}

Instead of a peek function, I built a peeker function that calls next, removing the element from the iterator, but then adds it back in by creating an iterable function that first yields the captured element, then yields the remaining items in the iterable.

function peeker(iterator) {
    let peeked = iterator.next();
    let rebuiltIterator = function*() {
        if(peeked.done)
            return;
        yield peeked.value;
        yield* iterator;
    }
    return { peeked, rebuiltIterator };
}

function* someIterator () { yield 1; yield 2; yield 3; }
let iter = someIterator();
let peeked = peeker(iter);

console.log(peeked.peeked);
for(let i of peeked.rebuiltIterator())
    console.log(i);

Translating @Shlang's answer to AsyncIterables and TypeScript:

type PeekableAsyncIterable<T> = AsyncIterable<T> & {
  peek: () => Promise<T | null>;
}

/**
 * Adds a `peek` method to `AsyncIterable<T>`, which
 * peeks at the next element in the iterable without consuming it.
 */
export const peekable = <T>(asyncIterable: AsyncIterable<T>): PeekableAsyncIterable<T> => {
  let nextElPromise = asyncIterable[Symbol.asyncIterator]().next()

  const it = (async function * () {
    let nonEmpty = true
    while (nonEmpty) {
      const result = await nextElPromise
      nonEmpty = !result.done
      if (nonEmpty) {
        nextElPromise = asyncIterable[Symbol.asyncIterator]().next()
        yield result.value
      }
    }
  })() as unknown as PeekableAsyncIterable<T>

  it.peek = async () => {
    const result = await nextElPromise
    return result.done
      ? null // if you have a `Result<T>` or `Either<T, E>` type, use it here instead of null
      : result.value
  }

  return it
}

I'd like to contribute my way of solving this, based off of Shlang's answer, by creating a Peekable class.

Here it is in TypeScript:

class Peekable<T> implements Iterator<T, void> {
  public peek: IteratorResult<T, void>;
  constructor(private iterator: Iterator<T, void>) {
    this.peek = iterator.next();
  }
  next() {
    const curr = this.peek;
    this.peek = this.iterator.next();
    return curr;
  }
  [Symbol.iterator]() {
    return this;
  }
}

It can be used like any other iterator, only with an extra peek property that shows the result of the next iteration:

function* countDownFrom(n: number) {
  for (n; n > 0; n--) yield n;
}

const countDown = new Peekable(countDownFrom(15));
for (const num of countDown) {
  console.log(num);
  if (num === 7) {
    console.log("
发布评论

评论列表(0)

  1. 暂无评论