如何在Ruby中向哈希添加值
我在这个主题上做了很多研究,但在我尝试的每种情况下,哈希中的值似乎都会被替换。在此人选择输入新ID后,我希望将下一个人的姓名和年龄添加到哈希中。有人能给我解释一下为什么要替换键和值吗如何在Ruby中向哈希添加值,ruby,methods,hash,Ruby,Methods,Hash,我在这个主题上做了很多研究,但在我尝试的每种情况下,哈希中的值似乎都会被替换。在此人选择输入新ID后,我希望将下一个人的姓名和年龄添加到哈希中。有人能给我解释一下为什么要替换键和值吗 class Person def initialize(name, age) if name != nil || age != nil if @people != nil @people[name.__id__] = age.__id__ else
class Person
def initialize(name, age)
if name != nil || age != nil
if @people != nil
@people[name.__id__] = age.__id__
else
@people = {name => age}
end
else
puts "Invalid credentials."
end
end
attr_reader :people
end
class MainInit
def initialize()
options = ["y", "yes", "n", "no"]
choice = "y"
while choice.downcase == "y" || choice.downcase == "yes"
p "Enter Name:"
inputname = gets.chomp
p inputname
p "Enter Age:"
inputage = gets.chomp
p inputage
person = Person.new(inputname, inputage)
p person.people
p "Enter another ID?"
choice = gets.chomp
until options.include? choice.downcase
p "Invalid Choice"
p "Enter another ID?"
choice = gets.chomp
end
end
end
end
MainInit.new
我认为键值对被替换的原因是:
initialize
方法中的语句
if @people != nil
将始终计算为false
<代码>初始化在创建新对象时被调用,因此默认情况下,@people
尚未定义或设置,因此每次调用
person = Person.new(inputname, inputage)
它创建了一个新的人
,而不是将这个新的人添加到一个现有的散列中(我认为您正在尝试这样做)
如果将people
设置为类变量(@@people
),可能会起作用,但似乎您只是想在主程序中创建一个哈希,然后在其中添加新的条目
像这样的
people = Hash.new # Or even just people = {}
然后,当您要添加新的姓名/年龄条目时
people[name] = age
我没有尝试过,但我认为你的整个计划应该简化为这样:
people = Hash.new
options = ["y", "yes", "n", "no"]
choice = "y"
while choice.downcase == "y" || choice.downcase == "yes"
p "Enter Name:"
inputname = gets.chomp
p inputname
p "Enter Age:"
inputage = gets.chomp
p inputage
#person = Person.new(inputname, inputage)
people[inputname] = inputage
person = people[inputname]
p person.people
p "Enter another ID?"
choice = gets.chomp
until options.include? choice.downcase
p "Invalid Choice"
p "Enter another ID?"
choice = gets.chomp
end
让我解释一下为什么您会遇到所描述的问题,并为您如何更改代码提供一些建议
班级人员
class MainInit
def initialize
loop do
name = nil
loop do
print 'Enter Name: '
name = gets.strip
break unless name.empty?
end
puts "name is #{name}"
age = nil
loop do
print 'Enter Age: '
age = gets.strip
case age
when /^\d+$/ && ('10'..'120')
break
else
puts 'age must be between 10 and 120'
end
end
puts "age is #{age}"
person = Person.new(name, age)
puts "people is now #{Person.people}"
loop do
print "Enter another ID? "
case gets.chomp.downcase
when 'n', 'no'
return
when 'y', 'yes'
break
else
puts 'Invalid choice'
end
end
end
end
end
在类Person
中,您需要在类级别保存人员列表,这意味着使用类实例变量(例如@people
)或类变量(例如@@people
)。我和大多数鲁比学生一样,更喜欢前者。(原因超出了这个答案的范围,但你只需在谷歌上搜索“Ruby‘class instance variables’vs‘class variables’”,就可以找到很多关于这个主题的文章。你只需输入内部引号,就可以缩小搜索范围。)
要定义类实例变量@people,我们只需按如下方式输入它:
class Person
@people = {}
class << self
attr_accessor :people
end
def initialize(name, age)
self.class.people[name] = age
end
end
将元素添加到hash@person,因为self.class
是person
,而people
是访问器
现在看看类MainInit
类MainInit
class MainInit
def initialize
loop do
name = nil
loop do
print 'Enter Name: '
name = gets.strip
break unless name.empty?
end
puts "name is #{name}"
age = nil
loop do
print 'Enter Age: '
age = gets.strip
case age
when /^\d+$/ && ('10'..'120')
break
else
puts 'age must be between 10 and 120'
end
end
puts "age is #{age}"
person = Person.new(name, age)
puts "people is now #{Person.people}"
loop do
print "Enter another ID? "
case gets.chomp.downcase
when 'n', 'no'
return
when 'y', 'yes'
break
else
puts 'Invalid choice'
end
end
end
end
end
loop do…end
您可以看到,在一些地方,我使用了loop do…end
和break
退出循环。我非常喜欢这种构造,与循环相比,当…
或直到…
时,部分原因是它避免了需要输入一个开始条件进入循环,然后在循环中重复相同的条件。我也只是觉得它看起来更干净
当您离开循环时,在循环中创建的任何变量都不再存在,因此如果您想要变量的值(例如,name
和age
),则必须在循环的开头之外引用该变量。这就是为什么(也是唯一的原因)我有name=nil
和age=nil
。它不必是nil
;我可以把它们初始化成任何东西
使用案例
语句
获取年龄的循环使用以下case语句:
case age
when /^\d+$/ && ('10'..'120')
...
end
这需要一些解释。case
语句使用,而不是获取真实值。因此,当/^\d+$/
相当于:
/^\d+$/ === age
这和
/^\d+$/ =~ age
('10'..'120').cover?(age)
正则表达式只是确保所有年龄字符都是数字(例如,“39”)
同样地
('10'..'120') === age
与
/^\d+$/ =~ age
('10'..'120').cover?(age)
零碎物品
我使用了String#strip
来代替String#chomp
。这两种方法都会删除结尾的换行符,但strip
也会删除用户可能在输入字符串的开头或结尾输入的空格
对于字符串,我主要使用单引号,但字符串插值需要双引号。例如,我最初编写了put'name is#{name}
。打印的name is#{name}
。将其更改为put'name is#{name}
,正确地打印了name is Debra
示例
MainInit.new
Enter Name: Debra
name is Debra
Enter Age: 29
age is 29
people is now {"Debra"=>"29"}
Enter another ID? y
Enter Name: Billy-Bob
name is Billy-Bob
Enter Age: 58
age is 58
people is now {"Debra"=>"29", "Billy-Bob"=>"58"}
Enter another ID? u
Invalid choice
Enter another ID? n
@people
是一个实例变量,因此每个实例都有一个实例变量。每个实例只包含一个键/值对。我猜您希望将与所有实例变量关联的名称和年龄存储在@people
中。如果是这样,您需要将@people
设置为类实例变量(或使用类变量,如@@people)。你需要重新构造你的类,因为你想保持状态,你需要将attr\u reader:people
更改为attr\u accessor:people
,这样你就可以改变people散列的结构,我也不认为你使用\uu id\uuu
是正确的或必要的,并且移动MainInit的初始化方法中的所有逻辑
进入另一个方法,只在其中留下@people=Person.new(nil,nil)
,然后你可以调用你创建的新方法,例如mainit.new.new\u method
,而不是mainit.new
,在你的脚本末尾我很快会给你另一个答案。