如何在scala中实现惰性序列(可迭代)?
我想实现一个惰性迭代器,它在 3 级嵌套循环中的每次调用中生成下一个元素。
scala 中是否有与 c# 代码片段类似的内容:
foreach (int i in ...)
{
foreach (int j in ...)
{
foreach (int k in ...)
{
yield return do(i,j,k);
}
}
}
谢谢,Dudu
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
Scala 序列类型都有一个 .view 方法,该方法生成集合的惰性等效项。您可以在 REPL 中尝试以下操作(在发出
:silent
以阻止它强制集合打印命令结果之后):第一个将打印出数字 1 到 10,第二个将不会直到您实际尝试访问结果的这些元素。
Scala 中没有任何内容直接相当于 C# 的
yield
语句,它会暂停循环的执行。您可以使用分隔延续来实现类似的效果,为 scala 2.8 添加。Scala sequence types all have a .view method which produces a lazy equivalent of the collection. You can play around with the following in the REPL (after issuing
:silent
to stop it from forcing the collection to print command results):The first will print out the numbers 1 to 10, the second will not until you actually try to access those elements of the result.
There is nothing in Scala directly equivalent to C#'s
yield
statement, which pauses the execution of a loop. You can achieve similar effects with the delimited continuations which were added for scala 2.8.如果将迭代器与
++
连接在一起,您将得到一个在两者上运行的迭代器。reduceLeft
方法有助于将整个集合连接在一起。因此,将产生您想要的迭代器。如果您希望它比这更懒,您也可以在前两个
(1 to 2)
之后添加.iterator
。 (当然,将每个(1 到 2)
替换为您自己更有趣的集合或范围。)If you join iterators together with
++
, you get a single iterator that runs over both. And thereduceLeft
method helpfully joins together an entire collection. Thus,will produce the iterator you want. If you want it to be even more lazy than that, you can add
.iterator
after the first two(1 to 2)
also. (Replace each(1 to 2)
with your own more interesting collection or range, of course.)您可以在 序列理解 ://www.scala-lang.org/api/current/index.html#scala.collection.Iterator" rel="nofollow">Iterators 来获得你想要的:
如果你想创建一个惰性的 Iterable (而不是惰性迭代器)使用 Views 代替:
取决于惰性程度如果您愿意,您可能不需要对迭代器/视图的所有调用。
You can use a Sequence Comprehension over Iterators to get what you want:
If you want to create a lazy Iterable (instead of a lazy Iterator) use Views instead:
Depending on how lazy you want to be, you may not need all of the calls to iterator / view.
如果您的 3 个迭代器通常很小(即,您可以完全迭代它们而不用担心内存或 CPU),并且昂贵的部分是计算给定 i、j 和 k 的结果,您可以使用 Scala 的 Stream 类。
如果您的迭代器对于这种方法来说太大,您可以扩展这个想法并创建一个元组流,通过保留每个迭代器的状态来延迟计算下一个值。例如(尽管希望有人有更好的方法来定义乘积方法):
这种方法完全支持无限大小的输入。
If your 3 iterators are generally small (i.e., you can fully iterate them without concern for memory or CPU) and the expensive part is computing the result given i, j, and k, you can use Scala's Stream class.
If your iterators are too large for this approach, you could extend this idea and create a Stream of tuples that calculates the next value lazily by keeping state for each iterator. For example (although hopefully someone has a nicer way of defining the product method):
This approach fully supports infinitely sized inputs.
我认为下面的代码是您真正要寻找的...我认为编译器最终会将其翻译成与 Rex 给出的地图代码等效的内容,但更接近原始示例的语法:
您可以从输出显示,直到迭代 x 的下一个值时,才会调用“doIt”中的 print,这种风格的 for 生成器比一堆嵌套映射更容易读/写。
I think the below code is what you're actually looking for... I think the compiler ends up translating it into the equivalent of the map code Rex gave, but is closer to the syntax of your original example:
You can see from the output that the print in "doIt" isn't called until the next value of x is iterated over, and this style of for generator is a bit simpler to read/write than a bunch of nested maps.
把问题倒过来。将“do”作为闭包传递进去。这就是使用函数式语言的全部意义
Turn the problem upside down. Pass "do" in as a closure. That's the entire point of using a functional language
Iterator.zip
会做到这一点:Iterator.zip
will do it:只需阅读侧面显示的 20 个左右的第一个相关链接(实际上,当您第一次写下问题标题时向您显示的链接)。
Just read the 20 or so first related links that are show on the side (and, indeed, where shown to you when you first wrote the title of your question).