2

我有以下代码,它工作正常。

months = {"Feb"=>["day1", "day2"]}

i = 0
while i < 5 do
   months["Feb"][i] = "day#{i}"
   i += 1
end
puts months

$> {"二月"=>["day0", "day1", "day2", "day3", "day4"]}

但是,如果我删除了初始化散列的第一行或尝试即时将值添加到不同的散列键,我会得到一个未定义的“月”错误。

所以我很困惑。Ruby 不会允许你任意添加键到哈希中吗?我已经习惯了 Perl,你可以随意开始制作散列和数组。但是我知道 Perl 将哈希和数组视为单独的对象,而 Ruby 的所有内容都被认为是相同的,所以我不知道它是否与此有关(尽管 Perl 的方式可能是“草率的”^_^)

4

4 回答 4

1

您总是需要在 Ruby 中初始化变量。但是您可以按如下方式初始化哈希:

# Using {} to creates an empty hash
months = {}

# or create a new empty hash object from Hash class
months = Hash.new

# instead of
months = {"Feb"=>["day1", "day2"]}

在哈希中初始化一个数组:

# Array.new creates a new Array with size 5
# And values within Hash.new block are the default values for the hash
# i.e. When you call the Hash#[], it creates a new array of size 5
months = Hash.new { |hash, key| hash[key] = Array.new(5) }
puts months        #=> {}
puts months["Feb"] # Here the Hash creates a new Array inside "Feb" key
puts months        #=> {"Feb" => [nil, nil, nil, nil, nil]}
puts months["Feb"][3] = "Day3"
puts months        #=> {"Feb" => [nil, nil, nil, "Day3", nil]}

要使用未定义的数组大小执行相同操作:

months = Hash.new { |hash, key| hash[key] = [] }
puts months        #=> {}
months["Feb"].push "Day0"
puts months        #=> {"Feb" => ["Day0"]}
months["Feb"].push "Day1"
puts months        #=> {"Feb" => ["Day0", "Day1"]}

我认为更优雅的方法是使用 map 方法在将其绑定到“Feb”键之前构建您的天数:

months = {"Feb" => (0..4).map{ |i| "day#{i}" }}
# => {"Feb"=>["day0", "day1", "day2", "day3", "day4"]}

如果您不想输入月份名称,则可以要求 Date 类并通过 Fixnum 获取月份名称:

require 'date'
months = {Date::ABBR_MONTHNAMES[2] => (0..4).map{ |i| "day#{i}"}}
# => {"Feb"=>["day0", "day1", "day2", "day3", "day4"]}

要为所有月份生成相同的结构,您可以执行以下操作:

days   = (0..4).map{ |d| "day#{d}"}
months = (1..12).map{ |m| {Date::ABBR_MONTHNAMES[m] => days }}
# => {"Jan"=>["day0", "day1", "day2", "day3", "day4"],
#     "Feb"=>["day0", "day1", "day2", "day3", "day4"],
#     ...
#     "Dec"=>["day0", "day1", "day2", "day3", "day4"]}

一些有用的文档:

于 2012-10-13T14:55:13.543 回答
1

在 Ruby 中,您必须在使用它之前初始化一个变量(看起来像是一个合理的策略......)。另请注意,您编写的不是惯用的 Ruby,而是一种替代方法:

months = {"Feb" => 0.upto(4).map { |i| "day#{i}" }}

更新:

months["Feb"] = 0.upto(4).map { |i| "day#{i}" }
于 2012-10-13T11:32:13.010 回答
0

根据你们所说的,我搞砸了,看起来 Ruby 希望密钥存在,然后才能开始为该密钥分配值。

hashname = Hash.new
hashname[:foo] = {}
hashname[:foo][3] = "test"
hashname[:foo][1] = "test1"
hashname[:bar] = {}
hashname[:bar][3] = "test3"
puts hashname
puts hashname[:foo][1]

C:\Ruby>scratch.rb
{:foo=>{3=>"test", 1=>"test1"}, :bar=>{3=>"test3"}}
test1

一旦密钥存在,您就可以根据需要开始分配值。尽管在这种情况下,您可以看到我正在创建“哈希哈希”而不是“数组哈希”,就像 .map 方法所做的那样,我仍然不知道为什么。

谢谢您的帮助!

于 2012-10-14T07:29:58.147 回答
0
# the ||= set this to an empty hash({}) if it hasn't been initialized yet
months ||= {}

#updated as you like, use symbols :feb over string "feb" as the key (read this in other questions in this website)
months[:feb] = (0..4).map {|n| "day#{n}"}

p months  #==> {:feb=>["day0", "day1", "day2", "day3", "day4"]}
于 2012-10-13T14:35:50.690 回答