如何在Scala中调用一个方法n次?

发布于 2024-12-05 22:34:23 字数 728 浏览 0 评论 0原文

我有一个例子,我想调用一个方法 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 循环,但这不是一个漂亮的功能解决方案。

I have a case where I want to call a method n times, where n is an Int. Is there a good way to do this in a "functional" way in 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
    }
}

I think a closure is a good solution for this, but I can't get it working. I have also tried with a for-loop, but it's not a beautiful functional solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

世界等同你 2024-12-12 22:34:23

我认为最简单的解决方案是使用范围:

(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() 

The simplest solution is to use range, I think:

(1 to n) foreach (x => /* do something */)

But you can also create this small helper function:

implicit def intTimes(i: Int) = new {
    def times(fn: => Unit) = (1 to i) foreach (x => fn)
}

10 times println("hello")

this code will print "hello" 10 times. Implicit conversion intTimes makes method times available on all ints. So in your case it should look like this:

event.quantity times queue.enqueue(event.value) 
event.quantity times queue.dequeue() 
话少情深 2024-12-12 22:34:23

不完全是您问题的答案,但如果您有同态(即转换 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

Not quite an answer to your question, but if you had an endomorphism (i.e. a transformation A => A), then using scalaz you could use the natural monoid for Endo[A]

N times func apply target

So that:

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
一笔一画续写前缘 2024-12-12 22:34:23

一个更实用的解决方案是使用带有不可变队列和 Queuefilldrop 方法的折叠:

 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)
}}

这并不能直接回答你的问题(如何调用函数指定的次数),但这绝对更惯用。

A more functional solution would be to use a fold with an immutable queue and Queue's fill and drop methods:

 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)
   }
 }

Or even better, capture your "supply"/"sale" distinction in subclasses of Event and avoid the awkward Option[BigDecimal] business:

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)
}}

This doesn't directly answer your question (how to call a function a specified number of times), but it's definitely more idiomatic.

英雄似剑 2024-12-12 22:34:23
import List._

fill(10) { println("hello") }

简单、内置,您将获得单位列表作为纪念品!

但如果您进行函数式编程,则永远不需要多次调用函数。

import List._

fill(10) { println("hello") }

Simple, built-in, and you get a List of Units as a souvenier!

But you'll never need to call a function multiple times if you're programming functionally.

北座城市 2024-12-12 22:34:23

通过递归:

def repeat(n: Int)(f: => Unit) { 
  if (n > 0) {
    f
    repeat(n-1)(f)
  }
}

repeat(event.quantity) { queue.enqueue(event.value) }

With recursion:

def repeat(n: Int)(f: => Unit) { 
  if (n > 0) {
    f
    repeat(n-1)(f)
  }
}

repeat(event.quantity) { queue.enqueue(event.value) }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文