deepin中zz
The FizzBuzz problem is a classic test given in coding interviews. The task is simple:
FizzBuzz问题是编码面试中的经典测试。 任务很简单:
Print integers 1 to N, but print “Fizz” if an integer is divisible by 3, “Buzz” if an integer is divisible by 5, and “FizzBuzz” if an integer is divisible by both 3 and 5.
打印从1到N的整数,如果将整数除以3,则打印“ Fizz”;如果将整数除以5,则打印“ Buzz”;如果将整数3和5均除,则打印“ FizzBuzz”。
There are many ways to achieve the desired output, but some methods are better than others. Great solutions to FizzBuzz don’t “just work”. They adhere to good programming principles, allow flexibility for later changes, and play to a language’s strengths. With these things in mind, solving FizzBuzz is a great exercise for learning the specifics of a language and generally improving your programming.
有多种方法可以实现所需的输出,但是有些方法比其他方法更好。 FizzBuzz的出色解决方案“不可行”。 他们遵循良好的编程原则,可以灵活地进行以后的更改,并发挥语言的优势。 考虑到这些问题,解决FizzBuzz是学习语言细节并总体上改善编程的绝佳练习。
Below, I’ve explained five approaches to the FizzBuzz problem using R. Understanding each one will help to reinforce good coding practices and the use of R’s unique features. It might even help you get hired.
下面,我解释了使用R解决FizzBuzz问题的五种方法。了解每种方法将有助于加强良好的编码习惯和R的独特功能。 它甚至可以帮助您被录用。
Note: although I explain all the code in this article, I assume a basic knowledge of fundamental programming principles and R data structures.
注意:尽管我解释了本文中的所有代码,但我假设您具有基本的编程原理和R数据结构的基本知识。
1.天真的解决方案 (1. A Naive Solution)
The most obvious way of solving FizzBuzz is to loop through a set of integers. In this loop, we use conditional statements to check whether each integer is divisible by 3 and/or 5.
解决FizzBuzz的最明显方法是遍历一组整数。 在此循环中,我们使用条件语句检查每个整数是否可被3和/或5整除。
The code above takes this approach. First, we store integers 1–50 in the vector fbnums
. An empty vector named output
is also defined to store the results of the procedure. Then, we check whether each integer in fbnums is evenly divisible by 3 and/or 5 using conditional statements within a for loop. These statements use the modulo operator %%
, which returns the remainder of a division operation. As an example, the expression if (i %% 3 == 0)
means “if we divide this integer by 3, is the remainder zero?”.
上面的代码采用了这种方法。 首先,我们将1–50的整数存储在向量fbnums
。 还定义了一个名为output
的空向量来存储过程的结果。 然后,我们使用for循环中的条件语句检查fbnums中的每个整数是否可以被3和/或5均分。 这些语句使用模运算符%%
,该运算符返回除法运算的余数。 例如,表达式if (i %% 3 == 0)
表示“如果将这个整数除以3,则余数为零吗?”。
When one of the conditional statements returns true, the appropriate response is stored in the ith index of the output
vector. Once the loop has completed, we print output
to display the results of the process.
当条件语句之一返回true时,适当的响应将存储在output
向量的第i个索引中。 循环完成后,我们将打印output
以显示过程结果。
While this code works, it has several limitations:
尽管此代码有效,但它有几个限制:
- It uses a lot of messy conditional statements, which are hard to maintain. 它使用了很多混乱的条件语句,很难维护。
The statements
i %% 3 == 0
andi %% 5 == 0
are repeated twice, making the code less efficient and more verbose.语句
i %% 3 == 0
和i %% 5 == 0
重复两次,使代码效率降低且更加冗长。- The for loop is relatively slow and inefficient in R, especially with many iterations. for循环在R中相对较慢且效率低下,尤其是在许多迭代中。
Luckily, there are a few ways to improve upon this starting point.
幸运的是,有一些方法可以改善这个起点。
2.使用For循环的更好解决方案 (2. A Better Solution Using a For Loop)
It’s possible to reduce the number of conditional statements in our for loop, as shown below. This was inspired by an example by Tom Scott from his video on the FizzBuzz problem, which I’d highly recommend watching.
可以减少for循环中条件语句的数量,如下所示。 灵感来自汤姆·斯科特(Tom Scott)的有关FizzBuzz问题的视频中的一个例子,我强烈建议您观看。
Here, fbnums
and output
are defined as they were before. But in the for loop, things work a little differently. First, we define the ith index in our output
vector as a blank string. We then check whether our integer is divisible by 3 as in the last example. If this returns true, we paste “Fizz” onto the end of the blank string in output[i]
. The equivalent statement for 5 and “Buzz” is evaluated in the next line. Finally, we check whether output[i]
is empty. If so, we store the integer in this element to avoid returning a blank string. Once the loop is over, printing output
gives the same result as the previous example.
在这里, fbnums
和output
的定义与以前一样。 但是在for循环中,工作原理有所不同。 首先,我们将output
向量中的第i个索引定义为空白字符串。 然后,如上例所示,检查整数是否可被3整除。 如果返回true,则将“ Fizz”粘贴到output[i]
空白字符串的末尾。 下一行将评估5和“嗡嗡声”的等效语句。 最后,我们检查output[i]
是否为空。 如果是这样,我们将整数存储在此元素中,以避免返回空字符串。 循环结束后,打印output
将得到与前面示例相同的结果。
This implementation is better than the previous for several reasons:
由于以下几个原因,该实现比以前的实现更好:
- Pasting “Fizz” and “Buzz” onto a blank string like this eliminates the need for a statement evaluating “FizzBuzz”. This gets rid of repetition and looks neater. 像这样将“ Fizz”和“ Buzz”粘贴到空白字符串上,就无需使用评估“ FizzBuzz”的语句。 这样可以避免重复,看起来更整洁。
- The format makes adding extra conditions trivial, while keeping the code readable. 该格式使得添加额外条件变得微不足道,同时保持代码可读性。
This is good progress, but the use of a for loop still doesn’t leverage some of R’s unique features. The next three examples take full advantage of these and are great for picking up some advanced R techniques.
这是一个很好的进步,但是for循环的使用仍然没有利用R的某些独特功能。 接下来的三个示例充分利用了这些优点,非常适合采用一些高级R技术。
3.使用FizzBuzzR的打包解决方案 (3. A Package Solution Using FizzBuzzR)
One of R’s strengths is its variety of user-friendly packages. FizzBuzzR is one of these and contains a single function meant for tackling the FizzBuzz problem. Calling fizzbuzz
allows the user to specify the range of integers to evaluate, the interval by which to step through these integers, and the divisors for “Fizz” and “Buzz”. The output is then printed line by line in the console.
R的强项之一是其各种易于使用的软件包。 FizzBuzzR是其中之一,并且包含用于解决FizzBuzz问题的单个功能。 调用fizzbuzz
允许用户指定要评估的整数范围,逐步遍历这些整数的时间间隔以及“ Fizz”和“ Buzz”的除数。 然后在控制台中逐行打印输出。
This implementation has the obvious advantage of being incredibly concise. But there’s a tradeoff: limited options for customisation. Let’s say an interviewer asks you to replace “Fizz” with “Biff”, or to store the output straight to a list. In these cases, you’d have to think of a completely new approach to do these things.
此实现的明显优势是非常简洁。 但是需要权衡:定制的选项有限。 假设一位面试官要求您将“ Fizz”替换为“ Biff”,或将输出直接存储到列表中。 在这些情况下,您必须考虑一种全新的方法来执行这些操作。
4.使用map()的功能解决方案 (4. A Functional Solution Using map())
Rather than using a pre-written function, we can write our own FizzBuzz function and then apply this to each integer we want to evaluate.
无需使用预先编写的函数,我们可以编写自己的FizzBuzz函数,然后将其应用于我们要求值的每个整数。
In the code above, we create a function called fbmap
that evaluates a given integer according to our FizzBuzz rules. Our function does this using the same conditional statements as in Example 2. This time around, however, we replace certain values with arguments that we can pass into the function. Our divisors, 3 and 5, are replaced with the arguments mod1
and mod2
, and our print statements “Fizz” and “Buzz” are replaced with exp1
and exp2
. This means that when we call the function, we can define these values as whatever we like without having to rewrite lots of code.
在上面的代码中,我们创建了一个名为fbmap
的函数,该函数根据FizzBuzz规则计算给定的整数。 我们的函数使用与示例2中相同的条件语句来执行此操作。但是,这次,我们将某些值替换为可以传递给函数的参数。 我们的除数3和5被替换为参数mod1
和mod2
,而我们的打印语句“ Fizz”和“ Buzz”被替换为exp1
和exp2
。 这意味着当我们调用函数时,我们可以将这些值定义为任意值,而无需重写大量代码。
To get our output, we apply our function to each element of the fbnums
vector using map_chr
. To do this, we use the expression ~ fbmap(.x, 3, 5, "Fizz", "Buzz")
inside map_chr
. This tells fbmap
to evaluate each element of the fbnums
vector (denoted as .x
) with the divisors 3 and 5, and responses “Fizz” and “Buzz”. The results of these successive function calls are stored as separate elements in output
, a character vector. Printing output
then displays the correct results in the console.
为了获得输出,我们使用map_chr
将函数应用于fbnums
向量的每个元素。 要做到这一点,我们使用表达式~ fbmap(.x, 3, 5, "Fizz", "Buzz")
内map_chr
。 这告诉fbmap
用除数3和5评估fbnums
向量的每个元素(表示为.x
),并响应“ Fizz”和“ Buzz”。 这些连续函数调用的结果作为单独的元素存储在output
(字符向量)中。 打印output
然后在控制台中显示正确的结果。
This implementation is great for a few reasons:
此实现之所以出色,有几个原因:
- It’s clear, concise, and avoids repetition. 清晰,简洁,避免重复。
Specifying arguments to
fbmap
provides flexibility. New conditions can also be added without complicating the codebase too much.为
fbmap
指定参数提供了灵活性。 也可以添加新条件,而不会使代码库过于复杂。It uses
map_chr
to apply a function across a vector, which is more efficient than using a for loop in R.它使用
map_chr
在向量上应用函数,这比在R中使用for循环更有效。
To me, this is a fairly strong FizzBuzz solution. It looks good, makes the most of R, and isn’t any longer than the naive implementation in my first example. But what if you’d like your FizzBuzz solution to be optimally compatible with a tidyverse workflow?
对我来说,这是一个相当强大的FizzBuzz解决方案。 它看起来不错,可以充分利用R,而且仅比我第一个示例中的幼稚实现长。 但是,如果您希望FizzBuzz解决方案与tidyverse工作流程最佳兼容,该怎么办?
5.使用case_when()的矢量化解决方案 (5. A Vectorised Solution Using case_when())
For most tasks in R, there’s a pre-defined tidyverse function that’ll help you out. Want to apply some if statements to elements of a vector? Use case_when
from the dplyr package.
对于R中的大多数任务,都有一个预定义的dydyverse函数可以帮助您。 是否要对向量元素应用某些if语句? 从dplyr软件包中使用case_when
。
The code above is modified from an example in the case_when
documentation, written by Hadley Wickham. Simply put, case_when
applies if statements across a vector and returns an output based on the result of these statements. This example also makes sure to return the integer in question when it isn’t evenly divisible, with the expression TRUE ~ as.character(fbnums)
. Minus some different syntax, this is exactly what we’ve been doing in the previous examples. The difference is that case_when
makes full use of R’s vectorisation capabilities, making it more efficient than the for loops in Solutions 1 and 2.
上面的代码是根据Hadley Wickham编写的case_when
文档中的示例修改的。 简而言之, case_when
适用于跨向量的if语句,并根据这些语句的结果返回输出。 此示例还确保在整数不能被整除时返回该整数,其表达式为TRUE ~ as.character(fbnums)
。 减去一些不同的语法,这正是我们在先前示例中所做的。 区别在于case_when
充分利用了R的向量化功能,使其比解决方案1和2中的for循环更有效。
On top of this, we still don’t repeat any conditional statements. Although we evaluate “FizzBuzz” as a separate condition, we can use simple maths to deduce that any instance of “FizzBuzz” is evenly divisible by 15, the lowest common factor of 3 and 5. This avoids the need for repeating statements containing %% 3 == 0
and %% 5 == 0
. Further, the code is still easy to read and add to if required. This could be achieved by adding more conditions to case_when
, or piping to another function after case_when
to fulfil more complicated requirements. All in all, case_when
is a great function for solving the FizzBuzz problem in R.
最重要的是,我们仍然不重复任何条件语句。 尽管我们将“ FizzBuzz”作为一个单独的条件进行评估,但我们可以使用简单的数学来推断“ FizzBuzz”的任何实例均可以被15整除,最小公因子3和5。这避免了重复包含%% 3 == 0
语句的需要。 %% 3 == 0
和%% 5 == 0
。 此外,该代码仍然易于阅读,并在需要时添加。 这可以通过在case_when
添加更多条件或在case_when
之后case_when
管道传递到另一个函数来满足更复杂的要求来实现。 总而言之, case_when
是解决R中的FizzBuzz问题的强大功能。
结论 (Conclusion)
Solving the FizzBuzz problem demonstrates the value of learning to write neat code. While every solution above works, some are far easier to maintain in a large real-life codebase. Why are these implimentations better? They adhere to good programming principles, and make the most of R’s capabilities.
解决FizzBuzz问题证明了学习编写简洁代码的价值。 尽管上述每种解决方案都可以使用,但是在大型现实代码库中维护起来却容易得多 。 为什么这些内含更好? 他们遵循良好的编程原则,并充分利用R的功能。
So the next time you code something, interview task or otherwise, ask yourself a few things. Am I repeating myself? How can I play to the strengths of my chosen language? Is the code I’m writing easy to maintain? Answering these questions won’t just help you write a good FizzBuzz solution. They’ll make you a better programmer.
因此,下次您编写代码,进行面试或其他任务时,请问自己几件事。 我在重复自己吗? 我如何发挥自己选择的语言的优势? 我编写的代码易于维护吗? 回答这些问题不仅可以帮助您编写出色的FizzBuzz解决方案。 它们将使您成为更好的程序员。
翻译自: https://towardsdatascience.com/how-to-solve-the-fizzbuzz-problem-in-r-c62e7e6c959a
deepin中zz