[翻译]Ruby教程11——哈希表

哈希表

这部分的教程我们将提到哈希表。哈希表是一个键-值对的集合。与数组相似,不同与数组的是哈希表的索引是确定的,数组的只能是整数。哈希表有时称为相关联的数组。


哈希表是非常有用的集合。它有许多方法供程序员使用。


创建哈希表


有两种创建哈希表的方式:使用new关键字或者哈希表的字面量。


#!/usr/bin/ruby

names = Hash.new
names[1] = “Jane”
names[2] = “Thomas”

puts names

第一个脚本创建了一个哈希表并添加了两个键-值对。


names = Hash.new

创建一个哈希对象。


names[1] = “Jane”
names[2] = “Thomas”

添加两对值。数字1、2是哈希表的键。键放在中括号里。names是属于键的值。


puts names

打印哈希表。


$ ./create.rb
{1=>”Jane”, 2=>”Thomas”}

从输出结果我们看到一个哈希表是用花括号括起来的。键和值是使用=>符号成对搭配。




store方法可以用于给哈希表设置一些初始值。它可以代替花括号。


#!/usr/bin/ruby

names = Hash.new
names.store(1, “Jane”)
names.store(2, “Thomas”)
names.store(3, “Rebecca”)

puts names

创建了一个相似的脚本,这次我们使用store方法。


names.store(1, “Jane”)

store方法的第一个参数是键,第二个参数是值。




第三个脚本我们使用字面符来创建哈希表。它的值是用花括号括起来的。并且键和值是用=>符号成对分配。


#!/usr/bin/ruby

domains = { “de” => “Germany”,
“sk” => “Slovakia”,
“hu” => “Hungary”,
“us” => “United States”,
“no” => “Norway”
}

puts domains[“de”]
puts domains[“sk”]

创建哈希表domains包含5对内容。这里键和值都是字符串。


$ ./create3.rb

Germany

Slovakia


例子的输出结果。


基本用法


这一节我们展示Ruby哈希表的一些很基础的方法。


#!/usr/bin/ruby

names = Hash.new

names[1] = “Jane”
names[2] = “Thomas”
names[3] = “Robert”
names[4] = “Julia”
names[5] = “Rebecca”

puts “The size of the hash is #{names.size}”

puts names.keys.inspect
puts names.values.inspect

上面的脚本中创建了一个有5个值的哈希表,介绍了哈希表的三个方法。


puts “The size of the hash is #{names.size}”

size方法返回哈希表的大小。与length方法相同。


puts names.keys.inspect
puts names.values.inspect

keys方法返回哈希表的所有键。以此类推,values方法返回哈希表的所有值。返回的数据是一个数组形式的。为了使输出更加可读我们使用了inspect方法。


$ ./basic.rb

The size of the hash is 5

[1, 2, 3, 4, 5]

[“Jane”, “Thomas”, “Robert”, “Julia”, “Rebecca”]


例子的输出结果。注意最后两个方法是两个数组。




这节的第二个例子展示了哈希表实例的三个方法。


#!/usr/bin/ruby

names1 = Hash.new

names1[1] = “Jane”
names1[2] = “Thomas”
names1[3] = “Robert”
names1[4] = “Julia”
names1[5] = “Rebecca”

names2 = names1.dup

puts names1.eql? names2

puts names1.empty?
names1.clear
puts names1.empty?

创建了一个names哈希表,对该对象调用了三个方法。


names2 = names1.dup

通过dup方法创建了一个副本。


puts names1.eql? names2

eql?方法比较两个哈希表对象是否相等。这里是相同的,打印true。


puts names1.empty?

empty?方法检查哈希表是否为空。这行打印false,因为names1有5项数据。


names1.clear
puts names1.empty?

clear方法删除哈希表的所有内容。接着调用empty?方法返回true。


$ ./basic2.rb

true

false

true


输出结果。




有一个方法可以判断一个键或者值是否在这个哈希表中。


#!/usr/bin/ruby

domains = { :de => “Germany”, :sk => “Slovakia”,
:no => “Norway”, :us => “United States”
}

puts domains.has_key? :de
puts domains.include? :no
puts domains.key? :me
puts domains.member? :sk

puts domains.has_value? “Slovakia”
puts domains.value? “Germany”

创建了一个有4对数据的哈希表domains。键是用的符号,因为它更有效。


puts domains.has_key? :de
puts domains.include? :no
puts domains.key? :me
puts domains.member? :sk

这里我们用了四个方法来判断哈希表是否包含该键。它们的功能都是相同的。


puts domains.has_value? “Slovakia”
puts domains.value? “Germany”

这里用了两个方法检查这两个字符串是否在哈希表中。


$ ./has.rb

true

true

false

true

true

true


输出结果。




这节的最后一个例子,我们将从哈希表中读取内容。


#!/usr/bin/ruby

stones = { 1 => “garnet”, 2 => “topaz”,
3 => “opal”, 4 => “amethyst”
}

puts stones.fetch 1
puts stones[2]
puts stones.values_at 1, 2, 3

这个脚本展示了三个读取值的方法。


puts stones.fetch 1

fetch方法通过给定的键读取值。


puts stones[2]

也可以使用中括号来获取一个值,这行会打印“topaz”


puts stones.values_at 1, 2, 3

values_at方法可以一次获取多个值。这个方法通过给定的键返回一个数组包含了对应的值。


$ ./read.rb

garnet

topaz

garnet

topaz

opal


例子的输出结果。


循环遍历哈希表


有一些方法可以用于循环遍历哈希表。


#!/usr/bin/ruby

stones = { 1 => “garnet”, 2 => “topaz”,
3 => “opal”, 4 => “amethyst”
}

stones.each { |k, v| puts “Key: #{k}, Value: #{v}” }
stones.each_key { |key| puts “#{key}” }
stones.each_value { |val| puts “#{val}” }
stones.each_pair { |k, v| puts “Key: #{k}, Value: #{v}” }

上面的例子我们展示的四个方法。用这些方法显示了所有的键、值。


stones.each { |k, v| puts “Key: #{k}, Value: #{v}” }

each方法对每个键都调用了给定的代码块,键-值对作为参数传递。


stones.each_key { |key| puts “#{key}” }

我们使用each_key方法循环遍历了哈希表所有的键。将它们打印在终端上。


stones.each_value { |val| puts “#{val}” }

each_value用于循环遍历哈希表所有的值。


stones.each_pair { |k, v| puts “Key: #{k}, Value: #{v}” }

each_pair方法与each方法相同。


$ ./loop.rb

Key: 1, Value: garnet

Key: 2, Value: topaz

Key: 3, Value: opal

Key: 4, Value: amethyst

1

2

3

4

garnet

topaz

opal

amethyst

Key: 1, Value: garnet

Key: 2, Value: topaz

Key: 3, Value: opal

Key: 4, Value: amethyst


输出结果。


删除键值对


接下来的例子关注哈希表的删除。


#!/usr/bin/ruby

names = Hash.new

names[1] = “Jane”
names[2] = “Thomas”
names[3] = “Robert”
names[4] = “Julia”
names[5] = “Rebecca”

names.delete 4
names.shift

puts names

这个脚本我们使用了两个方法:deleteshiftdelete方法是删除指定的键的值,并将其返回。shift方法删除哈希表的第一对键值,并将其作为数组返回。


names.delete 4

删除4 => “Julia”这对值。


names.shift

这行代码删除1 => “Jane”这对值。


$ ./deleteitem.rb
{2=>”Thomas”, 3=>”Robert”, 5=>”Rebecca”}

输出结果显示还剩的内容。




rejectdelete_if方法可以从哈希表中移除多项内容。如果这些方法所给定的代码块中的条件式返回true,则删除对应的键值对。这两个方法有个重要区别。reject方法作用于复本,delete_if作用于原对象。


#!/usr/local/bin/ruby

names1 = Hash.new

names1[1] = “Jane”
names1[2] = “Thomas”
names1[3] = “Robert”
names1[4] = “Julia”
names1[5] = “Rebecca”

puts names1.reject { |k, v| v =~ /R./ }
puts names1
puts names1.delete_if { |k, v| k<=3 }
puts names1

这个例子使用上面的方法删除多项键值对。


puts names1.reject { |k, v| v =~ /R./ }

reject方法移除所有满足代码块中正则式的值,并返回修改后的哈希表,原哈希表不变。


puts names1

这行的输出证实了原哈希表没有改变。


puts names1.delete_if { |k, v| k<=3 }

这里我们删除键小于等于3的键值对。这个方法修改了原对象。


$ ./massdelete.rb
{1=>”Jane”, 2=>”Thomas”, 4=>”Julia”}
{1=>”Jane”, 2=>”Thomas”, 3=>”Robert”, 4=>”Julia”, 5=>”Rebecca”}
{4=>”Julia”, 5=>”Rebecca”}
{4=>”Julia”, 5=>”Rebecca”}

输出结果。


添加内容


mergeupdate方法可以给哈希表添加键值对。


#!/usr/bin/ruby

names1 = Hash.new

names1[1] = “Jane”
names1[2] = “Thomas”

names2 = Hash.new

names2[3] = “Robert”
names2[4] = “Julia”

names = names1.merge names2
puts names

names = names1.update names2
puts names

这个脚本中我们创建了两个哈希表,然后对它们调用了mergeupdate方法。


names = names1.merge names2
puts names

合并names1names2,结果分配给names


$ ./merge.rb
{1=>”Jane”, 2=>”Thomas”, 3=>”Robert”, 4=>”Julia”}
{1=>”Jane”, 2=>”Thomas”, 3=>”Robert”, 4=>”Julia”}

最后的哈希表包含了names1names2的内容。


merge与merge!


最后一节,我们重述一下Ruby的习俗。一些Ruby的方法以感叹号结尾。这个标志在语法上没有意义,它只是表明调用这个方法会修改对象的内容。


#!/usr/bin/ruby

names1 = Hash.new

names1[1] = “Jane”
names1[2] = “Thomas”

names2 = Hash.new

names2[3] = “Robert”
names2[4] = “Julia”

names = names1.merge names2
puts names
puts names1

names = names1.merge! names2
puts names
puts names1

我们展示了mergemerge!方法的不同。


names = names1.merge names2

merge不会修改names1,它作用于一个新的复本。


names = names1.merge! names2

merge!方法作用于原对象。names1被修改了。


$ ./merge2.rb
{1=>”Jane”, 2=>”Thomas”, 3=>”Robert”, 4=>”Julia”}
{1=>”Jane”, 2=>”Thomas”}
{1=>”Jane”, 2=>”Thomas”, 3=>”Robert”, 4=>”Julia”}
{1=>”Jane”, 2=>”Thomas”, 3=>”Robert”, 4=>”Julia”}

merge2.rb程序的输出。


在这章我们学习了Ruby的哈希表。




原文地址: http://zetcode.com/lang/rubytutorial/hashes/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial