学习红宝石。需要返回一个长度为n的数组,其中给定数字x,然后是前一个数字的平方

发布于 2025-01-16 06:45:36 字数 982 浏览 1 评论 0原文

这就是问题

完成返回一个长度为 n 的数组的函数,从给定的数字 x 和前一个数字的平方开始。如果 n 为负数或零,则返回空数组/列表。

Examples
2, 5  -->  [2, 4, 16, 256, 65536]
3, 3  -->  [3, 9, 81]

对于我一直在学习的东西来说似乎很简单。

我已经完成了大部分代码,因为它完成了示例:

def squares(x, n)
array = [x]

i = 1
  while i < n
  array << x *= x

    i += 1

  end

  return array
end
PASS Test.assert_equals(squares(2,5),[2,4,16,256,65536]);  
PASS Test.assert_equals(squares(3,3),[3,9,81]);  
PASS Test.assert_equals(squares(5,3),[5,25,625]);  
PASS Test.assert_equals(squares(10,4),[10,100,10000,100000000]);

我遇到的麻烦是,该问题还要求 n 为正整数,如果不是,则返回一个空数组:

如果n为负数或零,则返回空数组/列表。

我很难弄清楚如何正确地解决这个问题。我尝试了几种不同的方法,但没有成功。这是我的一次尝试的例子,我认为我走在正确的轨道上:

def squares(x, n)
array = [x]
arr = []

i = 1
  if n < 0
    return arr
  elsif i < n
    array << x *= x
  end

    i += 1
 end
end

This is the problem

Complete the function that returns an array of length n, starting with the given number x and the squares of the previous number. If n is negative or zero, return an empty array/list.

Examples
2, 5  -->  [2, 4, 16, 256, 65536]
3, 3  -->  [3, 9, 81]

Seems easy enough for what Ive been learning.

Ive completed the code for the most part as it completes the examples:

def squares(x, n)
array = [x]

i = 1
  while i < n
  array << x *= x

    i += 1

  end

  return array
end
PASS Test.assert_equals(squares(2,5),[2,4,16,256,65536]);  
PASS Test.assert_equals(squares(3,3),[3,9,81]);  
PASS Test.assert_equals(squares(5,3),[5,25,625]);  
PASS Test.assert_equals(squares(10,4),[10,100,10000,100000000]);

The trouble Im having is, the problem also calls for n to be a positive integer, and if not, return an empty array:

If n is negative or zero, return an empty array/list.

Im having difficulty figuring out how to correctly go about this. Ive tried several different ways, with no success. This is an example of one of my attempts where I thought I was on the right track:

def squares(x, n)
array = [x]
arr = []

i = 1
  if n < 0
    return arr
  elsif i < n
    array << x *= x
  end

    i += 1
 end
end

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

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

发布评论

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

评论(3

滥情稳全场 2025-01-23 06:45:36

一种方法是创建一个枚举器,然后获取所需数量的元素:

def squares(x, m)
  Enumerator.produce(x) { |n| n*n }.take(m)
end
squares(2, 5)
  #=> [2, 4, 16, 256, 65536]
squares(3, 5)
  #=> [3, 9, 81, 6561, 43046721]

请参阅 枚举器::产生

One way is to create an enumerator and then take the required number of elements:

def squares(x, m)
  Enumerator.produce(x) { |n| n*n }.take(m)
end
squares(2, 5)
  #=> [2, 4, 16, 256, 65536]
squares(3, 5)
  #=> [3, 9, 81, 6561, 43046721]

See Enumerator::produce.

极致的悲 2025-01-23 06:45:36

只需在方法顶部添加以下行即可解决此问题:

return [] if n <= 0

尽管还有许多其他方法可以做到这一点。例如:

def squares(x, n)
  a = x
  (1..n).map { |e| a.tap { a *= a } }
end

这依赖于以下事实:如果 n <= mm..n 形式的 Ruby 范围不会产生任何元素。

Just adding the following line at the top of your method will solve it:

return [] if n <= 0

Though there are many other ways to do this. For example:

def squares(x, n)
  a = x
  (1..n).map { |e| a.tap { a *= a } }
end

This relies on the fact that Ruby ranges of form m..n produce no elements if n <= m.

余生再见 2025-01-23 06:45:36

首先我想说这个问题很愚蠢。不是的问题,我说的是问题陈述:

完成返回长度为 n 的数组的函数,从给定数字 x 和前一个数字的平方开始。如果 n 为负数或零,则返回空数组/列表。

它有几个问题。

  1. 它要求您返回一个 Array。在编程中,您应该始终努力使返回值尽可能通用,以便您的子例程可以在尽可能多的不同上下文中重用。如果您的子例程返回一个Array并且n非常大,那么Array将使用大量内存。但是,例如,如果有人只想迭代所有这些值,则不需要 Array。返回通常所说的或者Ruby所说的枚举器。如果客户端确实需要 Array,则可以轻松地将 Enumerator 转换为 Array
  2. 这同样适用于返回预定数量的元素 n 的要求。返回无限数量的元素并让客户端选择他们需要的数量会更有意义。例如,如果他们不知道元素的数量怎么办?如果他们想要将这些数字相加直到达到某个阈值怎么办?根据问题陈述的要求,他们必须猜测需要多少个数字才能达到该阈值,而如果你给他们一个无限流,他们可以迭代该流,直到找到答案。
  3. 这是我最讨厌的事情之一:问题陈述谈到了函数,但 Ruby 没有函数。它有方法。这是两件不同的事情。
  4. 它还将数组和列表视为同一事物。他们不是。
  5. [我将把这个放在括号中,因为无论哪种方式都可以争论。我认为 raise 更有意义 一个 Exception,更准确地说是一个 <一个href="https://ruby-doc.org/core/ArgumentError.html" rel="nofollow noreferrer">ArgumentError 表示负 n返回空结果。空结果对于 n == 0 有意义,但对于负 n 则不一定。]

因此,简而言之,问题陈述的措辞方式会导致糟糕的 Ruby 术语(函数、列表)和糟糕的编程实践(返回值太具体,没有正确地发出错误信号)。

无论如何,回到你的问题。

我遇到的麻烦是,该问题还要求 n 为正整数,如果不是,则返回一个空数组:

<块引用>

如果n为负数或零,则返回空数组/列表。

正如其他一些答案中提到的,您几乎可以直接将该语句翻译为 Ruby 代码:

# "If n is negative":
if n.negative?

# " …or zero":
if n.negative? || n.zero?

# "… return an empty array":
if n.negative? || n.zero? then return [] end

现在我们可以稍微优化一下。首先,如果您的条件表达式没有 else 分支,并且 then 分支中只有一个表达式,则可以使用所谓的修饰符 形式:

return [] if n.negative? || n.zero?

其次,“负数或零”只是“非正数”的另一种表达方式,这使我们能够简化条件:

return [] if !n.positive?

我们可以通过使用 条件表达式的倒置形式来使其更具可读性除非

return [] unless n.positive?

这满足问题陈述中的要求,但是,正如我提到的,我个人认为传递负长度应该是一个错误,所以我可能宁愿写这样的东西:

raise ArgumentError, "length must not be negative but you passed `#{n}`" if n.negative?
return [] if n.zero?

不过,正如我上面提到的,问题陈述的方式迫使你写该代码不是您在现实世界中实际编写的代码。在现实世界中,您会将问题分解为各种正交组件,并确保每个组件都可以单独使用。

原因是“特定长度的正方形序列”是一个非常具体的问题,这使得其他人不太可能遇到完全相同的问题,因此不太可能您的代码可以重复使用。

我会将此问题至少分解为以下子问题:

  1. 给定一个子例程来生成一个无限流来生成下一个元素。
  2. 从无限流中获取指定数量的元素。
  3. 一个数字的平方。

如果您已经解决了这三个子问题,则可以使用以下解决方案来解决特定问题:(1) 生成 (3) 个正方形的无限流,以及 (2) 仅采用前 n 个元素。

这种方法有什么优点?我看到两个主要问题:

  • 您已将问题分解为更简单的子问题:这三个子问题中的每一个都比原始问题更简单。因此,这三个问题每一个问题都比原来的问题更容易解决。一旦解决了这三个子问题,原来的问题就变得很容易解决,因为你只需要把这三个子问题连接在一起即可。
  • 您已经构建了一个包含三个通用解决方案的库,这些解决方案在解决原始问题之外非常有用。您也可以使用它们来解决其他问题。

事实上,我已经向您隐藏了最重要的好处:还记得我多次说过,让问题变得更普遍有助于使解决方案更可重用,从而使解决方案在更多情况下变得有用吗?好吧,事实证明,#1 和 #2 非常通用,并且在很多上下文中都很有用,以至于它们已经是为我们写的!! #1 和 #2 的解决方案是 Ruby 核心库的一部分,因此我们甚至不需要自己编写它们。

您可以使用方法 生成无限的 Enumerator Enumerator::product,这是 展开又名变形。您可以从 Enumerable 使用 Enumerable#take 。所以,我们剩下要解决的就是如何对一个数进行平方,这很简单。

您还会注意到,当您传递 0 作为元素数量并 raise 时,Enumerable#take 返回一个空的 Array > 当您传递负数时,会出现 ArgumentError,因此通过分解我们的问题并将子问题 #2 的解决方案委托给 Enumerable#take,我们也会得到该错误,并且我们想要的边缘情况行为免费。。

您已经可以在 Cary Swoveland 的回答中看到生成的代码是什么样子,所以我在这里不再重复。相反,我想展示我一开始的意思,当时我说返回无限的正方形流会更有用,因为客户可以应用自己的标准来确定要采用的元素数量。记住我提出的问题:

如果他们想要将这些数字相加直到达到某个阈值怎么办?根据问题陈述的要求,他们必须猜测需要多少数字才能达到该阈值,而如果你给他们一个无限流,他们可以迭代该流,直到找到答案。

如果我们这样编写我们的方法:

def infinite_stream_of_squares_starting_with(initial_value)
  Enumerator.produce(initial_value) { _1 * _1 }
end

那么客户端所要做的就是将 Enumerable#take (这允许它们获取特定数量的元素)替换为 Enumerable#take_while (允许它们在特定条件下获取元素是 :

def squares_until_sum_reaches_threshold(initial_value, threshold)
  sum = 0
  infinite_stream_of_squares_starting_with(initial_value).
    take_while { (sum += _1) < threshold }
end

因此,总而言之,将问题分解为子问题并概括这些子问题总是一个好主意,因为分解问题使问题变得更简单,而概括则使其更有可能在以下方面有用 其他情况,并且更有可能已经被其他人解决了。特别是,您应该始终将 I/O 与计算分开,并尝试将生成数据、转换数据、过滤数据和减少数据彼此分开。

First off, I would like to say that the question is stupid. Not your question, I am talking about the problem statement:

Complete the function that returns an array of length n, starting with the given number x and the squares of the previous number. If n is negative or zero, return an empty array/list.

There are several things wrong with it.

  1. It requires you to return an Array. In programming, you should always strive to make your return values as generic as possible, so that your subroutine can be re-used in as many different contexts as possible. If your subroutine returns an Array and n is very large, then the Array will use a lot of memory. However, if someone just wants to iterate over all of those values, for example, there is no need for an Array. It would make much more sense to return what is commonly called a stream or what Ruby calls an Enumerator. A client can easily convert an Enumerator to an Array if they really need an Array.
  2. The same applies to the requirement to return a pre-determined number of elements n. It would make much more sense to return an infinite number of elements and let the client pick the number they need. For example, what if they don't know the number of elements? What if they want to sum those numbers until they reach a certain threshold? With the requirement from the problem statement, they would have to guess how many numbers they need in order to reach that threshold, whereas if you give them an infinite stream, they can just iterate the stream until they have found their answer.
  3. This is one of my pet peeves: the problem statement talks about functions, but Ruby doesn't have functions. It has methods. Those are two different things.
  4. It also treats arrays and lists as if they were the same thing. They are not.
  5. [I'll put this one in parentheses, because it can be argued either way. I think it would make more sense to raise an Exception, more precisely an ArgumentError for a negative n instead of returning an empty result. The empty result makes sense for n == 0, but not necessarily for negative n.]

So, in short, the way the problem statement is worded promotes bad Ruby terminology (function, list) and bad programming practices (too specific return value, not properly signaling errors).

Anyway, back to your question.

The trouble Im having is, the problem also calls for n to be a positive integer, and if not, return an empty array:

If n is negative or zero, return an empty array/list.

As mentioned in some of the other answers, you can almost literally translate that statement to Ruby code:

# "If n is negative":
if n.negative?

# " …or zero":
if n.negative? || n.zero?

# "… return an empty array":
if n.negative? || n.zero? then return [] end

Now we can optimize this a little bit. First off, if you have a conditional expression with no else branch and only a single expression in the then branch, you can use the so-called modifier form:

return [] if n.negative? || n.zero?

Secondly, "negative or zero" is just a different way of saying "not positive", which allows us to simplify the condition:

return [] if !n.positive?

We can make this more readable by using the inverted form of the conditional expression with unless:

return [] unless n.positive?

This satisfies the requirement in the problem statement, however, as I mentioned, I personally think passing a negative length should be an error, so I would probably rather write something like this:

raise ArgumentError, "length must not be negative but you passed `#{n}`" if n.negative?
return [] if n.zero?

As I mentioned above, though, the way the problem statement forces you to write the code is not how you would actually write it in the real world. In the real world, you would decompose the problem into various orthogonal components, and make sure that each of those components can also be used separately.

The reason is that "a sequence of squares of a specific length" is a very specific problem, which it makes it very unlikely that someone else is going to have the exact same problem, and thus makes it unlikely that your code can be re-used.

I would decompose this problem into at least these subproblems:

  1. Produce an infinite stream given a subroutine to produce the next element.
  2. Take a specified number of elements from an infinite stream.
  3. Square a number.

If you have solved these three subproblems, you can solve the specific problem using the solutions by (1) producing an infinite stream of (3) squares and (2) taking only the first n elements.

What are the advantages of this approach? I see two major ones:

  • You have broken the problem down into simpler subproblems: each of those three subproblems is simpler than the original problem. Therefore, each of the three problems is easier to solve than the original one. Once you have solved the three subproblems, the original problem also becomes easy to solve because you just have to plug the three subproblems together.
  • You have built a library of three general solutions that are useful beyond the original problem. You can use these to solve other problems as well.

In fact, I have hidden the most important benefit from you: remember how I said multiple times that making the problem more general helps make the solution more reusable, so that the solution becomes useful in more contexts? Well, it turns out that #1 and #2 are so general and so useful in so many contexts, that they have already been written for us! The solutions to #1 and #2 are part of the Ruby core library, so we don't even need to write them ourselves.

You can produce an infinite Enumerator using the method Enumerator::produce, which is Ruby's name for an unfold aka Anamorphism. And you can take a specified number of elements from an Enumerable using Enumerable#take. So, all that's left for us to solve here is how to square a number, which is trivial.

You will also note that Enumerable#take returns an empty Array when you pass 0 as the number of elements and raises an ArgumentError when you pass a negative number, so by decomposing our problem and delegating the solution of sub-problem #2 to Enumerable#take we also get the error and edge case behavior we want for free.

You can already see in Cary Swoveland's answer what the resulting code looks like, so I will not repeat it here. Rather, I want to show what I meant at the very beginning when I said that returning an infinite stream of squares would be more useful because the client could then apply their own criterion for how many elements to take. Remember the problem I posed:

What if they want to sum those numbers until they reach a certain threshold? With the requirement from the problem statement, they would have to guess how many numbers they need in order to reach that threshold, whereas if you give them an infinite stream, they can just iterate the stream until they have found their answer.

If we write our method like this:

def infinite_stream_of_squares_starting_with(initial_value)
  Enumerator.produce(initial_value) { _1 * _1 }
end

Then all the client has to do is to replace Enumerable#take (which allows them to take a specific number of elements) with Enumerable#take_while (which allows them to take elements while a specific condition is met), and they can write:

def squares_until_sum_reaches_threshold(initial_value, threshold)
  sum = 0
  infinite_stream_of_squares_starting_with(initial_value).
    take_while { (sum += _1) < threshold }
end

So, in summary, it is always a good idea to break down problems into subproblems and generalize those subproblems, because breaking the problem down makes it simpler, and generalizing makes it both more likely to be useful in other contexts, and more likely to already have been solved by someone else. In particular, you should always separate I/O from computation, and try to separate generating data, transforming data, filtering data, and reducing data from each other.

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