for (i <- 1 to 100) {
if ( i % 3 == 0 && i% 5 == 0)
println(i +" = FizzBuzz")
else if (i % 3 == 0)
println(i +" = Fizz")
else if (i % 5 == 0)
println(i +" = Buzz")
}
#1 楼
FizzBuzz是一个困难的例子,因为它的简单性意味着每种语言在外观上都差不多。就是说,我们可以全力以赴强调Scala的功能方面。首先,我们可以将FizzBuzz的核心逻辑包装在其自身的功能中:
def fizzBuzz(x:Int) = {
if (x % 15 == 0)
"FizzBuzz"
else if (x % 3 == 0)
"Fizz"
else if (x % 5 == 0)
"Buzz"
else
x
}
现在,我们可以通过打印进行组合,并将其映射到我们感兴趣的领域:
(1 until 100).map(fizzBuzz _ andThen println)
请注意,在哪里在Java中,我们可能会在每种情况下都重复使用一流的功能在Scala中使用
println
,我们可以轻松地将其分离出来作为过程中自己的步骤。当这种情况的优点变得更加明显时,我们考虑重新组合元素。例如,如果我们愿意,我们可以将所有内容连接成一个字符串,而无需重写基本的FizzBuzzzing逻辑:
println((1 until 100).map(fizzBuzz).mkString(", "))
因此,希望您可以看到Scala的“更好”方式”是一流的功能。有了它们,我们可以更轻松地组成系统的各个部分。
#2 楼
或者,如果您更喜欢匹配/大小写而不是if / else:(1 until 100).map(i => (i % 3, i % 5) match {
case (0, 0) => "FizzBuzz"
case (0, _) => "Fizz"
case (_, 0) => "Buzz"
case _ => i
}).foreach(println)
更新:
所以我们在这里正在做的是数字列表并将它们首先映射到元组,其中左侧是数字模块3,右侧是模5。然后,将这些元组匹配到两个都是零,左为零,右为零或都不为零的情况。
实际的逻辑也位于映射块中,而打印的副作用在foreach块中。
评论
\ $ \ begingroup \ $
IMO是迄今为止提出的最灵活的解决方案。 map()优于循环标准,并且此处的匹配比链式if / else优雅得多。
\ $ \ endgroup \ $
–geoffjentry
2014年2月2日在16:24
\ $ \ begingroup \ $
一些评论:#1使用1到100表示范围1-99#2我们不需要映射,因为我们不会重复使用fizz,buzz和fizzbuzz字符串的集合。直截了当的foreach也行得通。
\ $ \ endgroup \ $
–龙婆
16/09/23在12:00
#3 楼
而不是同时使用3和5:
if (i % 3 == 0 && i % 5 == 0)
您可以只使用15:
if (i % 15 == 0)
如果两种情况都不适用,您也应该自己打印数字:
else
println(i)
对于现有的情况,您只应打印该消息。
最终解决方案:
for (i <- 1 to 100) {
if (i % 15 == 0)
println("FizzBuzz")
else if (i % 3 == 0)
println("Fizz")
else if (i % 5 == 0)
println("Buzz")
else
println(i)
}
#4 楼
有点老了,但是这是我的两分钱:您可以使用PartialFunction。基本上,您可以定义要使用的函数并以适当的顺序进行组合:
def f(divisor: Int, result: Int => String): PartialFunction[Int, String] = {
case i if (i % divisor == 0) => result(i)
}
val f3 = f(3, _ => "Fizz")
val f5 = f(5, _ => "Buzz")
val f15 = f(15, x => f3(x) + f5(x)) // DRY
val id = f(1, _.toString)
val fizzBuzz = f15 orElse f3 orElse f5 orElse id
(1 to 100).map(fizzBuzz andThen println)
必须先调用
f15
,否则f3
或f5
将停止合成。以同样的方式,
id
是最后一个后备时间(任何数字都是模1)并打印输入(这就是为什么我定义result
作为一个函数,而不仅仅是一个字符串。)#5 楼
我试图提出一种不同的解决方案。我并不是说它会更好,但是我认为我应该把它放在这里,因为这种方法可能更适合于某些与FizzBuzz相关的应用程序。基本上我会分别处理fizz和buzz问题并合并它们。我还使用了很多Scala功能,例如Stream,Option,currying和case匹配。
def transformPeriodic(period: Int, word: String)(counter: Int) =
if (counter % period == 0) Some(word) else None
val fizzTransform = transformPeriodic(3, "Fizz") _
val buzzTransform = transformPeriodic(5, "Buzz") _
def mergeFizzBuzz(fizzOpt: Option[String], buzzOpt: Option[String]): Option[String] = {
(fizzOpt, buzzOpt) match {
case (None, None) => None
case _ => Some(fizzOpt.getOrElse("") + buzzOpt.getOrElse(""))
}
}
val streamInt = Stream.from(1)
val tripletStream = streamInt.map(i => (i, fizzTransform(i), buzzTransform(i)))
val doubletStream = tripletStream.map { case (i, fizzOpt, buzzOpt) => (i, mergeFizzBuzz(fizzOpt, buzzOpt)) }
val fizzBuzzStream = doubletStream.map { case (i, fizzBuzzOpt) => fizzBuzzOpt.getOrElse(i) }
fizzBuzzStream take 15 foreach println
#6 楼
这利用了scala的功能类型:val wordMap = Seq(3 -> "Fizz", 5 -> "Buzz")
(1 to 100).map(i => {
Some(
wordMap.collect({ case (num, str) if i % num == 0 => str}).mkString
).filterNot(_.isEmpty).getOrElse(i.toString)
}).foreach(println)
如果包含附加的数字到单词的映射,它也很容易扩展(例如,对于被7整除的所有数字,也打印
"Bazz"
。所有数字都被“ 10”除以10的整数),只需更改wordMap
:val wordMap = Seq(3 -> "Fizz", 5 -> "Buzz", 7 -> "Bazz", 10 -> "Ten")
(1 to 100).map(i => {
Some(
wordMap.collect({ case (num, str) if i % num == 0 => str}).mkString
).filterNot(_.isEmpty).getOrElse(i.toString)
}).foreach(println)
一些相关文献:用Monad过度思考FizzBuzz
#7 楼
通常,我们将使该解决方案更加实用。也就是说,将“ fizzbuzz”逻辑移动到返回字符串的内容中,然后使用该代码:def fizzbuzz(i: Int) =
if (i % 3 == 0 && i % 5 == 0) "FizzBuzz"
else if (i % 3 == 0) "Fizz"
else if (i % 5 == 0) "Buzz"
else s"$i"
for (i <- 1 to 100) println(fizzbuzz(i))
这是一件小事,但它涉及到哲学上的差异。
评论
\ $ \ begingroup \ $
作为免责声明,我不是Scala专家,因此可以对代码进行一些清理。尽管如此,基本要点还是一样。
\ $ \ endgroup \ $
– Beyamor
2014年2月2日,9:59
\ $ \ begingroup \ $
嘿,这很酷-我喜欢。这是我一直在寻找的回应。思想上确实有点转变,我认为像FizzBuzz这样的简单示例就很清楚了。
\ $ \ endgroup \ $
– jcm
2014年2月2日,11:19
\ $ \ begingroup \ $
@cookiemonster,您可能还想看看Clojure中的高阶FizzBuzz。我认为计算pi(在20个有争议的编程意见中排名第18)是因为它不那么简单(不难,但不那么简单),实际上在功能世界中确实需要一些不同的思考。
\ $ \ endgroup \ $
–user22048
2014年2月2日在18:20
\ $ \ begingroup \ $
尽管x%15 == 0和x%3 == 0 && x%5 == 0得出相同的结果,但它们在概念上并不相同。
\ $ \ endgroup \ $
– jmoreno
14-10-27在2:39