首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Fizz,Buzz还是FizzBuzz?

Fizz,Buzz还是FizzBuzz?
EN

Code Review用户
提问于 2016-11-29 12:11:44
回答 2查看 1.2K关注 0票数 9

几天前,我们的电话系统坏了,我在网上闲逛。我偶然发现了R编程语言。现在我不是编程专家,但我喜欢到处乱搞不同的语言,我相信它能帮助我成为一个更好的程序员。因此,我决定尝试为那些不知道fizzbuzz是什么的人解决R中的fizzbuzz挑战:

编写一个将数字从1打印到100的程序。但对于三种印刷品的倍数,"Fizz“而不是数字,以及五种打印"Buzz”的倍数。对于三倍和五倍的数字,请打印"FizzBuzz“

这是我在R中写的第一件事,我想对我迄今所取得的成就做一些评论:

代码语言:javascript
复制
fizzBuzz = function(range, x, y){
    for (i in seq(1, range, by=1)){
        if (i %% x == 0 & i %% y == 0){
            print('FizzBuzz')
        }
        else if (i %% y ==0){
            print('Buzz')
        }
        else if (i %% x == 0){
            print('Fizz')
        }
        else{
            print(i)
        }
    }
}
fizzBuzz(100, 3, 5)

一些关键的事情,我想要关注,每一个规范,可以自由地批评一切;

  1. 把所有这些都放在一个函数中是不是有点过火了,很明显,我可以简单地不使用这个函数,但是在R中,将解决方案放入函数中是否被认为是一个好的实践呢?我之所以问这个问题,是因为我环顾了一下人们的代码,并没有看到太多的函数。
  2. 是否有更简单的方法来创建范围?我觉得seq(from, to, by=1)range(from, to)更难理解
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-11-30 00:42:54

要回答你最初的问题:

  1. 总的来说,我不能代表R良好实践--但我喜欢函数,而且我仍然重用在我的第一个R脚本中创建的许多函数。它们在并行化方面也很好地工作。
  2. 您可以使用范围速记语法(如1:n )来创建从1到n的范围。或者,在您的用例中,seq(1, n)就足够了。

此外:

  1. 打印值通常不是很有用。并行/矢量化不能很好地工作。在R演播室中,您可以将值存储在变量中,并在以后使用它们;这将不适用于正在进行的打印。
  2. 根据我的经验,基于循环的方法非常慢。考虑使用lapply
  3. 我更喜欢<-而不是=,只是为了提醒我它不是C。(非常主观的)当它不是顶级赋值(例如,命名参数)时,由于作用域的不同,我使用=

我会这样写。我还包含了一个并行函数,当range足够高时,并行化的工作速度要比lapply快。该代码补充了一个迷你基准,我已经调整了您的for-循环代码,使之兼容,并在适当的情况下内联整数3和5。

代码语言:javascript
复制
# Run this once to install benchmark suite:
#install.packages(c("microbenchmark", "stringr"), dependencies = TRUE)
require(microbenchmark)
library(parallel)

# Setup parallelization particulars.
cores <- detectCores()
cluster <- makeCluster(cores)

gerardFizzBuzz <- function(i) {
    fizz <- i %% 3
    buzz <- i %% 5

    if (fizz == 0 & buzz == 0) {
      return('FizzBuzz')
    }
    else if (buzz == 0) {
      return('Buzz')
    }
    else if (fizz == 0) {
      return('Fizz')
    }

    return(i)
}

applyFizzBuzz <- function(range) {
    return(lapply(1:range, gerardFizzBuzz))
}

parallelFizzBuzz <- function(range) {
    return(parLapply(cluster, 1:range, gerardFizzBuzz))
}

vectorizedFizzBuzz <- function(range) {
    v <- Vectorize(gerardFizzBuzz)
    return(v(1:range))
}

papasmurfFizzBuzz <- function (range) {
    res <- seq(1, range)

    for (i in res){
      if (i %% 3 == 0 & i %% 5 == 0){
        res[i] <- 'FizzBuzz'
      }
      else if (i %% 5 ==0){
        res[i] <- 'Buzz'
      }
      else if (i %% 3 == 0){
        res[i] <- 'Fizz'
      }
      else{
        res[i] <- i
      }
    }

    return(res)
}

range <- 100000;

perf <- microbenchmark(applyFizzBuzz(range), vectorizedFizzBuzz(range), parallelFizzBuzz(range), papasmurfFizzBuzz(range), times=20)

# note the log scale.
boxplot(perf, names = c("lapply", "Vectorized", "parLapply", "forloop"))

stopCluster(cluster)

这是使用range <- 100000times=20在我的机器(4个核)上运行上述脚本的结果。

票数 5
EN

Code Review用户

发布于 2016-12-27 11:10:40

为了添加到@flodel的注释中,这里有一个适当的向量化版本。人们可以看到,这要快得多,比并行选项(在7个核上)的性能要高出一个因子5。这个问题很好地证明了为什么值得花时间思考向量化代码:

代码语言:javascript
复制
flodel_fizzbuzz <- function(range = 100, fizz = 3, buzz = 5) {
  s <- 1:range
  is.fizz <- s %% fizz == 0
  is.buzz <- s %% buzz == 0

  s[is.fizz] <- 'Fizz'
  s[is.buzz] <- 'Buzz'
  s[is.fizz & is.buzz] <- 'FizzBuzz'
  return(s)
}

运行@Gerard回答的基准测试(请注意,vectorizedFizzBuzz并没有真正向量化):

代码语言:javascript
复制
Unit: milliseconds
                      expr       min        lq      mean    median        uq       max neval  cld
      applyFizzBuzz(range) 296.52224 303.19205 315.76901 309.18860 320.01676 384.18786    20   c 
 vectorizedFizzBuzz(range) 341.41121 356.82580 374.53857 362.45300 372.81459 461.65169    20    d
   parallelFizzBuzz(range) 117.40058 128.91812 158.66095 153.87976 170.76776 288.99613    20  b  
  papasmurfFizzBuzz(range) 292.22177 301.48002 316.31151 307.31605 319.05426 393.53235    20   c 
    flodel_fizzbuzz(range)  27.98101  29.15677  29.93554  29.93097  30.84586  32.09304    20 a   
  1. 我确实认为函数是执行这些任务的好方法。
  2. 创建一系列后续整数的最简单方法是使用:

这个tidyverse版本的性能也差不多( ~40 ms):

代码语言:javascript
复制
tidy_fizbuzz <- function(range = 100, fizz = 3, buzz = 5) {
  x <- 1:range
  dplyr::case_when(
    x %% (fizz * buzz) == 0 ~ "Fizz Buzz",
    x %% fizz == 0 ~ "Fizz",
    x %% buzz == 0 ~ "Buzz",
    TRUE ~ as.character(x)
  )
}
票数 11
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/148439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档