提问人:Brandon Hill 提问时间:8/29/2016 最后编辑:Todd A. JacobsBrandon Hill 更新时间:8/29/2016 访问量:367
为什么我的 Ruby for 循环不会在我的回文方法中遍历 String?
Why won't my Ruby for-loop iterate over a String in my palindrome method?
问:
我在让我的 for 循环处理字符串时遇到了问题。这只是一种简单的方法来判断一个单词是否是回文(一个前后拼写相同的单词)。我已经多次调整了for循环,但在下面不断收到相同的错误消息。谁能为我指出正确的方向?
法典:
def palindrome?(string)
string2 = ""
for i in string
string2 = string[i] + string2
end
if string2 == string1
return true
end
end
palindrome?("abcba")
错误:
hours.rb:7:in `palindrome?': undefined method `each' for 5:Fixnum (NoMethodError)
from hours.rb:17:in `<main>'
答:
问题是你不能遍历一个字符串(例如,在Python中)。您首先需要将其转换为数组:.split
for c in string.split
string2 = c + string2
end
话虽如此,你不应该在 Ruby 中使用循环。它们在内部被转换为一种方法,因此您犯了令人困惑的错误。最好从一开始就写:for
each
each
string.split.each do |c|
string2 = c + string2
end
任何 Ruby 程序员都不会在任何情况下使用,它只被刚接触 Ruby 的人使用;-)for
请注意,Array.each
只是一个迭代方法;例如,还有 String.each_char
方法:
string.each_char do |c|
string2 = c + string2
end
最后,您的代码在其他几个位置不正确。我不会向你指出所有这些错误,因为如果你自己解决这个编程练习,它对你来说会更加有益和有教育意义;-)
评论
你要找的是:
def palindrome?(string)
string2 = ""
for i in 0...string.length
string2 = string[i] + string2
end
if string2 == string
return true
end
end
请注意,您可以更简单地定义它:
def palindrome?(string)
string == string.reverse
end
评论
你可以这样写:
def palindrome?(str)
str == str.reverse
end
评论
正如 Carpetsmoker 所指出的,你不能直接遍历字符串。但是,Ruby 为元素提供了正索引和负索引。负索引相对于数组或字符串的末尾定位。这使您可以非常有效地进行检查,并在确定没有回文后立即缩短测试:
def palindrome?(str)
(0...str.length/2).all? { |i| str[i] == str[-(i+1)] }
end
如果你想更加面向对象,你可以把它转换为类 String 中的方法:
class String
def palindrome?
(0...length/2).all? { |i| self[i] == self[-(i+1)] }
end
end
p "abcba".palindrome? # => true
注意 — 编辑以利用 Cary Swoveland 关于使用而不是从块中显式返回的出色建议。这使它成为单行。all?
TL;博士
除了效率低下之外,您的代码不起作用,因为 String 不是 Array,也不会混合在 Enumerator 中以提供 #each 方法。
虽然 String#[] 方法允许索引到字符串中,但没有要调用的 String#each 方法。因此,你不能在 Ruby for 循环中使用 String 对象,因为它只是 #each 的语法糖。
了解异常
我不确定您运行的是哪个版本的 Ruby,但是您在帖子中列出的异常在我的系统上无法重现。在 Ruby 2.3.1 上运行时,代码会生成一个相当明显的异常:
for i in string
string2 = string[i] + string2
end
NoMethodError:“abcba”:字符串的未定义方法“each”
这是相当荒谬的。它告诉你 String 没有 #each 方法,这就是语法糖在引擎盖下真正调用的内容。如果要迭代,则需要某种形式的 Enumerator 或 Enumerable 来使用。for i in string
遍历字符串
String 类具有许多有用的方法,用于将字符串转换为可迭代对象。一些例子包括:
- String#each_char 可以传递一个块,也可以返回一个枚举器
- String#chars 返回一个 Array
- String#split 还返回一个 Array(例如
'abcba'.split //
)
例如,您的代码可以重构为使用如下所示的块:
string = 'abcba'
tmpstr = ''
string.each_char { |char| tmpstr < char; puts true if tmpstr == 'abcba' }
#=> "abcba"
然而,虽然这突出了如何解决异常,但它仍然是不必要的复杂和低效的。
利用内置方法
除非你这样做是为了做家庭作业,否则在 Ruby 中这样做的正确方法是利用以 C 速度运行的内置方法,并且不会创建以后需要垃圾回收的临时 Ruby 对象。例如,要测试给定字符串是向后还是向前读取相同的内容,只需使用 String#reverse 和 String#eql? 方法将反向字符串与原始字符串进行比较即可。
def palindrome? str
str.reverse.eql? str
end
palindrome? 'abcba'
#=> true
palindrome? 'abcde'
#=> false
如果您愿意,也可以使用 String#== 而不是,但我认为在这种情况下使用后者更清晰。方法链清楚地表明,您正在调用 String 方法,而不是一些语言语法进行比较。在了解 Ruby 核心的来龙去脉时,这种区别可能是一个真正的帮助,但在这种情况下,无论哪种方式,结果都是一样的。#eql?
评论
下一个:对三个或更多对象进行相等性测试
评论