gpt4 book ai didi

dart - 意外的迭代器功能和Iterable.take行为

转载 作者:行者123 更新时间:2023-12-03 04:24:22 25 4
gpt4 key购买 nike

我正在编写一个称为批处理的简单函数,该函数应该将其可迭代地拆分为大小可变的可迭代对象。
然后,我遇到了生成器函数和Iterable.take方法的怪异行为(当期望/知道python生成器行为时)。

此代码:

Iterable<T> iterate<T>(Iterable<T> iterable) sync* {
print('generator started');
for (var item in iterable)
yield item;
}

void main() {
List l = [1, 2, 3, 4, 5];
final it = iterate(l);
print(it.take(2));
print(it.take(2));
}

输出:
generator started
(1, 2)
generator started
(1, 2)

而预期的输出是:
generator started
(1, 2)
(3, 4)
  • 为什么iterate被调用两次而不是在yield之后继续下一次迭代?
  • 是否可以通过内置或更优雅的方式编写以下变通办法?
    我的解决方法:

  • Iterable<List<T>> batches<T>(Iterable<T> iterable, int size) sync* {
    final iter = iterable.iterator;
    List group = takeN(iter, size).toList();
    while (group.length > 0){
    yield group;
    group = takeN(iter, size).toList();
    }
    }


    Iterable<T> takeN<T>(Iterator<T> iterator, int n) sync* {
    for (var i = 0; i < n && iterator.moveNext(); i++)
    yield iterator.current;
    }


    void main() {
    List l = [1, 2, 3, 4, 5];
    print(batches(l, 2));
    }

    最佳答案

    这就是迭代器和迭代器的工作方式。
    Iterable是一个简单的对象,在开始迭代之前它什么也不做。Iterator是维护迭代状态的代码。

    当您调用sync*函数时,它将立即返回Iterable
    当您开始迭代该可迭代对象时,通过读取其iterator getter并使用返回的Iteratorsync*函数主体开始运行。每次调用moveNext都会运行主体,直到下一个yield为止。

    每次获得新的iterator时,函数主体均从头开始。
    这就是为什么您的两个it.take(2)调用都做同样的事情的原因,每个工作都通过获取新的迭代器并两次调用moveNext来完成。

    至于您想做什么的更简单方法,也许是:

    Iterable<List<T>> batch<T>(Iterable<T> source, int size) {
    List<T> accumulator;
    for (var value in source) {
    (accumulator ??= []).add(value);
    if (accumulator.length == size) {
    yield accumulator;
    accumulator = null;
    }
    }
    if (accumulator != null) yield accumulator;
    }

    关于dart - 意外的迭代器功能和Iterable.take行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60684819/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com