为什么 Ruby 中有这个百分比错误?初学者学习
Why this % Error in Ruby ? Beginner Learning
我昨天刚开始Ruby。
我在网上看到了一些基础知识并开始做一些初学者编码挑战,其中一个要求寻找素数。我尽量不使用 Ruby 中已有的 prime 功能。
我想我差不多搞定了,但我不明白为什么会出现错误。
"18:in ': undefined method %' for nil:NilClass (NoMethodError)"
我试了几个小时来解决这个问题,但似乎无法在网上找到解决方案...
我使用 Ruby 3.0.0,这是我到目前为止设法构建的代码:
nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
prime_nums = []
i = 0
#Loop on the array to check each element
while i <= nums.length
check = 0
divider = nums[i]
#While to prevent DivisionByZero error
while divider != 0
if nums[i] % divider == 0 #/!\ ERROR HERE
check += 1
end
divider -= 1
end
#Only division by 1 and itself will increment $check
if check == 2
prime_nums.append(nums[i])
end
i += 1
end
puts prime_nums
在您的示例中,这意味着 nums[i]
returns 为零,因此情况是 i
大于 19。
您可以将 while i <= nums.length
更改为 while i < nums.length
,因为数组在 Ruby 中从 0 开始索引。
undefined method %' for nil:NilClass
表示您正尝试在 nil
上使用 %
。 nil
是当您尝试从数组中获取过多信息时得到的结果。
如果我们将 p "#{i}: #{nums[i]}"
放入循环中,我们将看到 i
变为 20。数组从 0 开始计数,因此如果数组中有 20 个元素,则最高索引为 19 . num[20]
是 nil
.
您可以通过 while i < nums.length
解决此问题以在 19 停止。
然而,很少有人在 Ruby 中编写 while
循环。相反,您使用方法进行迭代。 each
iterates through each element of an Array. And you can count down with downto
.
nums.each do |num|
check = 0
num.downto(1) do |divider|
if num % divider == 0
check += 1
end
end
#Only division by 1 and itself will increment $check
if check == 2
prime_nums.append(num)
end
end
现在没有机会差一分了。
@Schwern 的回答对在 Ruby 中使用迭代方法提出了很好的建议。我们可以使用它们来提高您的算法的效率。
def is_prime?(num)
2.upto Math::sqrt(num) do |divisor|
return false if num % divisor == 0
end
true
end
我们可以从 2
开始计算 num
的平方根,而不是从 num
向下迭代到 1
并跟踪除数。如果我们找到一个偶数除数,我们就知道它不是素数,并且可以立即 return false
,省去了我们进一步迭代任何东西的努力。
如果我们到达循环的末尾,我们知道 num
必须是质数并且 return true
.
然后假设我们要打印从 1
到 500
的素数,我们可以这样做:
1.upto 500 do |num|
puts num if is_prime? num
end
我昨天刚开始Ruby。 我在网上看到了一些基础知识并开始做一些初学者编码挑战,其中一个要求寻找素数。我尽量不使用 Ruby 中已有的 prime 功能。 我想我差不多搞定了,但我不明白为什么会出现错误。
"18:in ': undefined method %' for nil:NilClass (NoMethodError)"
我试了几个小时来解决这个问题,但似乎无法在网上找到解决方案... 我使用 Ruby 3.0.0,这是我到目前为止设法构建的代码:
nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
prime_nums = []
i = 0
#Loop on the array to check each element
while i <= nums.length
check = 0
divider = nums[i]
#While to prevent DivisionByZero error
while divider != 0
if nums[i] % divider == 0 #/!\ ERROR HERE
check += 1
end
divider -= 1
end
#Only division by 1 and itself will increment $check
if check == 2
prime_nums.append(nums[i])
end
i += 1
end
puts prime_nums
在您的示例中,这意味着 nums[i]
returns 为零,因此情况是 i
大于 19。
您可以将 while i <= nums.length
更改为 while i < nums.length
,因为数组在 Ruby 中从 0 开始索引。
undefined method %' for nil:NilClass
表示您正尝试在 nil
上使用 %
。 nil
是当您尝试从数组中获取过多信息时得到的结果。
如果我们将 p "#{i}: #{nums[i]}"
放入循环中,我们将看到 i
变为 20。数组从 0 开始计数,因此如果数组中有 20 个元素,则最高索引为 19 . num[20]
是 nil
.
您可以通过 while i < nums.length
解决此问题以在 19 停止。
然而,很少有人在 Ruby 中编写 while
循环。相反,您使用方法进行迭代。 each
iterates through each element of an Array. And you can count down with downto
.
nums.each do |num|
check = 0
num.downto(1) do |divider|
if num % divider == 0
check += 1
end
end
#Only division by 1 and itself will increment $check
if check == 2
prime_nums.append(num)
end
end
现在没有机会差一分了。
@Schwern 的回答对在 Ruby 中使用迭代方法提出了很好的建议。我们可以使用它们来提高您的算法的效率。
def is_prime?(num)
2.upto Math::sqrt(num) do |divisor|
return false if num % divisor == 0
end
true
end
我们可以从 2
开始计算 num
的平方根,而不是从 num
向下迭代到 1
并跟踪除数。如果我们找到一个偶数除数,我们就知道它不是素数,并且可以立即 return false
,省去了我们进一步迭代任何东西的努力。
如果我们到达循环的末尾,我们知道 num
必须是质数并且 return true
.
然后假设我们要打印从 1
到 500
的素数,我们可以这样做:
1.upto 500 do |num|
puts num if is_prime? num
end