几天前,我们的电话系统坏了,我在网上闲逛。我偶然发现了R编程语言。现在我不是编程专家,但我喜欢到处乱搞不同的语言,我相信它能帮助我成为一个更好的程序员。因此,我决定尝试为那些不知道fizzbuzz是什么的人解决R中的fizzbuzz挑战:
编写一个将数字从1打印到100的程序。但对于三种印刷品的倍数,"Fizz“而不是数字,以及五种打印"Buzz”的倍数。对于三倍和五倍的数字,请打印"FizzBuzz“
这是我在R中写的第一件事,我想对我迄今所取得的成就做一些评论:
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)一些关键的事情,我想要关注,每一个规范,可以自由地批评一切;
R中,将解决方案放入函数中是否被认为是一个好的实践呢?我之所以问这个问题,是因为我环顾了一下人们的代码,并没有看到太多的函数。seq(from, to, by=1)比range(from, to)更难理解发布于 2016-11-30 00:42:54
要回答你最初的问题:
1:n )来创建从1到n的范围。或者,在您的用例中,seq(1, n)就足够了。此外:
lapply。<-而不是=,只是为了提醒我它不是C。(非常主观的)当它不是顶级赋值(例如,命名参数)时,由于作用域的不同,我使用=。我会这样写。我还包含了一个并行函数,当range足够高时,并行化的工作速度要比lapply快。该代码补充了一个迷你基准,我已经调整了您的for-循环代码,使之兼容,并在适当的情况下内联整数3和5。
# 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 <- 100000和times=20在我的机器(4个核)上运行上述脚本的结果。

发布于 2016-12-27 11:10:40
为了添加到@flodel的注释中,这里有一个适当的向量化版本。人们可以看到,这要快得多,比并行选项(在7个核上)的性能要高出一个因子5。这个问题很好地证明了为什么值得花时间思考向量化代码:
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并没有真正向量化):
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 :。
这个tidyverse版本的性能也差不多( ~40 ms):
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)
)
}https://codereview.stackexchange.com/questions/148439
复制相似问题