如何在Scala中调用n次方法?
Posted
技术标签:
【中文标题】如何在Scala中调用n次方法?【英文标题】:How to call a method n times in Scala? 【发布时间】:2011-11-23 17:13:17 【问题描述】:我有一个例子,我想调用一个方法 n 次,其中 n 是一个 Int。在 Scala 中是否有一种以“函数式”方式执行此操作的好方法?
case class Event(name: String, quantity: Int, value: Option[BigDecimal])
// a list of events
val lst = List(
Event("supply", 3, Some(new java.math.BigDecimal("39.00"))),
Event("sale", 1, None),
Event("supply", 1, Some(new java.math.BigDecimal("41.00")))
)
// a mutable queue
val queue = new scala.collection.mutable.Queue[BigDecimal]
lst.map event =>
event.name match
case "supply" => // call queue.enqueue(event.value) event.quantity times
case "sale" => // call queue.dequeue() event.quantity times
我认为闭包是一个很好的解决方案,但我无法让它发挥作用。我也尝试过使用 for 循环,但这不是一个漂亮的功能解决方案。
【问题讨论】:
相关:***.com/questions/2842540/… 您不会获得具有可变队列的功能解决方案。 @Apocalisp:可变队列不是必需的。 【参考方案1】:不是你的问题的完全答案,但如果你有一个自同态(即转换 A => A
),那么使用 scalaz 你可以使用自然幺半群 Endo[A]
N times func apply target
这样:
scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._
scala> Endo((_:Int) * 2).multiply(5)
res3: scalaz.Endo[Int] = Endo(<function1>)
scala> res1(3)
res4: Int = 96
【讨论】:
猫是这样的吗?【参考方案2】:import List._
fill(10) println("hello")
简单、内置,你会得到一个单位列表作为纪念品!
但是,如果您使用函数式编程,则永远不需要多次调用函数。
【讨论】:
“但如果你在进行函数式编程,你永远不需要多次调用一个函数。” 如何在不调用“add”函数四次的情况下将四个数字添加到列表中? @Jonas Apocalisp 在他的评论中是正确的,如果您正在寻找函数式代码,则不应使用可变数据结构,因为其本质上需要命令式操作。 (这并不是说 mutable 不是最好的解决方案 - 有时它会是。但它不是函数式样式。)对于不可变结构,答案基本上是 a)递归,b)使用flatMap
与 List.fill
或(1 to n).map...
,或 c) 使用 for 表达式更清晰地执行此操作。 @missingfaktor 我的意思是在给定范围内使用相同的参数,这是没有意义的
@Luigi:确实有道理,因为这是将多个项目添加到队列中的唯一方法,就像本例一样。
@Jonas 具有像改变队列这样的副作用的方法不是一个函数——它是一个命令式过程。您正在询问如何使用函数来做一些必要的事情 - 将项目添加到可变队列中。由于根据定义,函数对于给定的参数总是返回相同的东西,并且没有副作用,这是不可能的。使用不可变队列将有助于您理解这一点。【参考方案3】:
更实用的解决方案是使用带有不可变队列和Queue
的fill
和drop
方法的折叠:
val queue = lst.foldLeft(Queue.empty[Option[BigDecimal]]) (q, e) =>
e.name match
case "supply" => q ++ Queue.fill(e.quantity)(e.value)
case "sale" => q.drop(e.quantity)
或者更好的是,在Event
的子类中捕获您的"supply"
/"sale"
区别,并避免尴尬的Option[BigDecimal]
业务:
sealed trait Event def quantity: Int
case class Supply(quantity: Int, value: BigDecimal) extends Event
case class Sale(quantity: Int) extends Event
val lst = List(
Supply(3, BigDecimal("39.00")),
Sale(1),
Supply(1, BigDecimal("41.00"))
)
val queue = lst.foldLeft(Queue.empty[BigDecimal]) (q, e) => e match
case Sale(quantity) => q.drop(quantity)
case Supply(quantity, value) => q ++ Queue.fill(quantity)(value)
这并不能直接回答您的问题(如何将函数调用指定次数),但它肯定更惯用。
【讨论】:
【参考方案4】:使用递归:
def repeat(n: Int)(f: => Unit)
if (n > 0)
f
repeat(n-1)(f)
repeat(event.quantity) queue.enqueue(event.value)
【讨论】:
【参考方案5】:我认为最简单的解决方案是使用范围:
(1 to n) foreach (x => /* do something */)
但你也可以创建这个小辅助函数:
implicit def intTimes(i: Int) = new
def times(fn: => Unit) = (1 to i) foreach (x => fn)
10 times println("hello")
此代码将打印“hello”10 次。隐式转换 intTimes
使方法 times
在所有整数上都可用。因此,在您的情况下,它应该如下所示:
event.quantity times queue.enqueue(event.value)
event.quantity times queue.dequeue()
【讨论】:
谢谢,但我不能使用第一个建议,因为我的queue.dequeue()
返回了BigDecimal
。
for (i <- 1 to n) /* do something */
比foreach
略短 :)
@Luigi Plinge:我认为 4 个额外的字符并没有太大的区别,但我同意,这对于理解来说看起来更好一点 :)
如何修改times
以将i
作为fn
的参数包含在内?示例:假设我想在您的示例中打印 "hello" + i
where i = 1 ... 10
@Kevin 你可以像这样重写times
函数:def times(fn: Int => Unit) = (1 to i) foreach fn
。现在的用法如下所示:10 times (i => println("hello" + i))
。因此,times
现在不再采用名称参数,而是采用 Int => Unit
函数作为参数。以上是关于如何在Scala中调用n次方法?的主要内容,如果未能解决你的问题,请参考以下文章