如何计算 Scala 中 for comprehension 的迭代次数?
How to count the number of iterations in a for comprehension in Scala?
我在流上使用 for comprehension,我想知道需要多少次迭代才能获得最终结果。
在代码中:
var count = 0
for {
xs <- xs_generator
x <- xs
count = count + 1 //doesn't work!!
if (x prop)
yield x
}
有办法实现吗?
编辑: 如果您不想 return 只有第一项,而是整个解决方案流,请查看第二部分。
Edit-2: 较短的版本附加了 zipWithIndex
。
不完全清楚您要做什么。在我看来,您似乎在尝试在列表流中查找某些内容,并另外保存已检查元素的数量。
如果这是您想要的,请考虑这样做:
/** Returns `x` that satisfies predicate `prop`
* as well the the total number of tested `x`s
*/
def findTheX(): (Int, Int) = {
val xs_generator = Stream.from(1).map(a => (1 to a).toList).take(1000)
var count = 0
def prop(x: Int): Boolean = x % 317 == 0
for (xs <- xs_generator; x <- xs) {
count += 1
if (prop(x)) {
return (x, count)
}
}
throw new Exception("No solution exists")
}
println(findTheX())
// prints:
// (317,50403)
几个要点:
- Scala 的 for-comprehension 与 Python 的 "yield" 没有任何关系。以防万一您认为他们这样做了:re-read for-comprehensions.
上的文档
- 没有 built-in 语法来中断 for-comprehensions。最好把它包装成一个函数,然后调用
return
。虽然也有 breakable
,但它适用于异常。
- 函数return是找到的项目和选中项目的总数,因此return类型是
(Int, Int)
。
- 在
for
-comprehension之后最后的错误是确保return类型是Nothing <: (Int, Int)
而不是Unit
,它不是子类型(Int, Int)
.
- 当您想以这种方式将
Stream
用于此类目的时请三思:生成前几个元素后,Stream
会将它们保存在内存中。如果 Stream 使用不当,这可能会导致 "GC-overhead limit exceeded"-错误。
再次强调:Scala for-comprehensions 中的 yield
与 Python 的 yield
无关。 Scala 没有 built-in 对协程和生成器的支持。您并不像您想象的那样经常需要它们,但它需要一些重新调整。
编辑
我又 re-read 你的问题了。如果您想要整个解决方案流以及已检查了多少个不同 x
的计数器,您可以使用类似的东西:
val xs_generator = Stream.from(1).map(a => (1 to a).toList)
var count = 0
def prop(x: Int): Boolean = x % 317 == 0
val xsWithCounter = for {
xs <- xs_generator;
x <- xs
_ = { count = count + 1 }
if (prop(x))
} yield (x, count)
println(xsWithCounter.take(10).toList)
// prints:
// List(
// (317,50403), (317,50721), (317,51040), (317,51360), (317,51681),
// (317,52003), (317,52326), (317,52650), (317,52975), (317,53301)
// )
注意 _ = { ... }
部分。 for
-理解中可以发生的事情数量有限:
- 生成器(
x <-
事物)
- filters/guards (
if
-s)
- 值定义
在这里,我们 sort-of 滥用 value-definition 语法来更新计数器。我们使用块 { counter += 1 }
作为赋值的右侧。它 returns Unit
。因为我们不需要块的结果,所以我们使用 _
作为赋值的左侧。这样,这个block每x
.
执行一次
EDIT-2
如果改变计数器不是您的主要目标,您当然可以直接使用 zipWithIndex
:
val xsWithCounter =
xs_generator.flatten.zipWithIndex.filter{x => prop(x._1)}
它给出的结果与以前的版本几乎相同,但是索引移动了 -1
(这是索引,而不是尝试的次数 x
-s)。
我在流上使用 for comprehension,我想知道需要多少次迭代才能获得最终结果。
在代码中:
var count = 0
for {
xs <- xs_generator
x <- xs
count = count + 1 //doesn't work!!
if (x prop)
yield x
}
有办法实现吗?
编辑: 如果您不想 return 只有第一项,而是整个解决方案流,请查看第二部分。
Edit-2: 较短的版本附加了 zipWithIndex
。
不完全清楚您要做什么。在我看来,您似乎在尝试在列表流中查找某些内容,并另外保存已检查元素的数量。
如果这是您想要的,请考虑这样做:
/** Returns `x` that satisfies predicate `prop`
* as well the the total number of tested `x`s
*/
def findTheX(): (Int, Int) = {
val xs_generator = Stream.from(1).map(a => (1 to a).toList).take(1000)
var count = 0
def prop(x: Int): Boolean = x % 317 == 0
for (xs <- xs_generator; x <- xs) {
count += 1
if (prop(x)) {
return (x, count)
}
}
throw new Exception("No solution exists")
}
println(findTheX())
// prints:
// (317,50403)
几个要点:
- Scala 的 for-comprehension 与 Python 的 "yield" 没有任何关系。以防万一您认为他们这样做了:re-read for-comprehensions. 上的文档
- 没有 built-in 语法来中断 for-comprehensions。最好把它包装成一个函数,然后调用
return
。虽然也有breakable
,但它适用于异常。 - 函数return是找到的项目和选中项目的总数,因此return类型是
(Int, Int)
。 - 在
for
-comprehension之后最后的错误是确保return类型是Nothing <: (Int, Int)
而不是Unit
,它不是子类型(Int, Int)
. - 当您想以这种方式将
Stream
用于此类目的时请三思:生成前几个元素后,Stream
会将它们保存在内存中。如果 Stream 使用不当,这可能会导致 "GC-overhead limit exceeded"-错误。
再次强调:Scala for-comprehensions 中的 yield
与 Python 的 yield
无关。 Scala 没有 built-in 对协程和生成器的支持。您并不像您想象的那样经常需要它们,但它需要一些重新调整。
编辑
我又 re-read 你的问题了。如果您想要整个解决方案流以及已检查了多少个不同 x
的计数器,您可以使用类似的东西:
val xs_generator = Stream.from(1).map(a => (1 to a).toList)
var count = 0
def prop(x: Int): Boolean = x % 317 == 0
val xsWithCounter = for {
xs <- xs_generator;
x <- xs
_ = { count = count + 1 }
if (prop(x))
} yield (x, count)
println(xsWithCounter.take(10).toList)
// prints:
// List(
// (317,50403), (317,50721), (317,51040), (317,51360), (317,51681),
// (317,52003), (317,52326), (317,52650), (317,52975), (317,53301)
// )
注意 _ = { ... }
部分。 for
-理解中可以发生的事情数量有限:
- 生成器(
x <-
事物) - filters/guards (
if
-s) - 值定义
在这里,我们 sort-of 滥用 value-definition 语法来更新计数器。我们使用块 { counter += 1 }
作为赋值的右侧。它 returns Unit
。因为我们不需要块的结果,所以我们使用 _
作为赋值的左侧。这样,这个block每x
.
EDIT-2
如果改变计数器不是您的主要目标,您当然可以直接使用 zipWithIndex
:
val xsWithCounter =
xs_generator.flatten.zipWithIndex.filter{x => prop(x._1)}
它给出的结果与以前的版本几乎相同,但是索引移动了 -1
(这是索引,而不是尝试的次数 x
-s)。