Ruby 哈希
最后修改于 2023 年 10 月 18 日
在本 Ruby 教程中,我们将学习 Ruby 哈希。
Ruby 哈希定义
Ruby 哈希 是一组键值对的集合。它类似于数组。与数组不同的是,哈希可以使用任意对象作为索引。数组只能使用整数。哈希以插入对应键的顺序枚举它们的值。哈希有时被称为关联数组。
哈希是强大的集合。它们有很多方法,程序员可以使用它们来完成工作。
Ruby 哈希创建
哈希可以通过两种基本方式创建:使用 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 是哈希的键。键放在方括号内。名称是属于键的值。
puts names
puts
方法将哈希的字符串表示形式打印到控制台。它也是哈希的字符串字面量。
$ ./create_hash.rb {1=>"Jane", 2=>"Thomas"}
从输出中,我们可以看到 names 哈希的字面量表示形式。哈希用大括号括起来。键和值用 =>
字符配对。
可以使用 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 对。这次键和值都是字符串类型。
domains = { "de" => "Germany", "sk" => "Slovakia", "hu" => "Hungary", "us" => "United States", "no" => "Norway" }
这是哈希字面量表示法。键值对放在大括号之间。项目由逗号分隔。键与值使用 =>
字符组合关联。
puts domains["de"]
在这里,我们打印与 "de" 键关联的域名值名称。
$ ./create_hash3.rb Germany Slovakia
Ruby 哈希的基本操作
在本节中,我们将介绍一些用于 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
在上面的 Ruby 脚本中,我们创建了一个包含五个值的哈希。我们介绍了三种哈希方法。
puts "The size of the hash is #{names.size}"
size
方法返回哈希的大小。它是 length
方法的同义词。
puts names.keys.inspect puts names.values.inspect
keys
方法返回哈希的所有键。类似地,values
方法返回哈希的所有值。返回的数据以数组的形式出现。为了使输出更具可读性,我们还对返回的数组调用 inspect
方法。
$ ./basic_work.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?
Ruby 脚本创建了一个 names 哈希。它在该对象上调用了三个哈希方法。
names2 = names1.dup
我们通过调用 dup
方法创建了哈希的副本。哈希从父对象继承了该方法。
puts names1.eql? names2
eql?
方法比较两个哈希对象。在我们的例子中,哈希相等,并且该行打印 true。
puts names1.empty?
empty?
方法检查哈希是否为空。该行打印 false,因为 names1 哈希有五个项目。
names1.clear puts names1.empty?
clear
方法从哈希中删除所有项目。连续调用 empty?
方法将返回 true。
$ ./basic_work2.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"
我们创建了一个 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"
这两种方法检查字符串是否在哈希中。
$ ./is_present.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
Ruby 脚本介绍了三种用于读取哈希值的哈希方法。
puts stones.fetch 1
fetch
方法读取给定键的值。
puts stones[2]
可以使用方括号获取一个值。在我们的例子中,该行将 "topaz" 打印到控制台。
puts stones.values_at 1, 2, 3
可以使用 values_at
方法一步获取多个值。该方法返回给定键的值的数组。
$ ./reading.rb garnet topaz garnet topaz opal
Ruby 哈希迭代
有几种方法可以用于循环 Ruby 哈希。
#!/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
方法的同义词。我们循环遍历 stones 哈希的键和值。
$ ./looping.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
输出显示了 stones 哈希的键和值、键和值。
Ruby 删除哈希中的键值对
在以下示例中,我们关注从哈希中删除键值对的方法。这包括删除单个键值对的方法以及可以一步删除多个键值对的方法。
#!/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
在脚本中,我们有两种方法:delete
和 shift
。delete
方法删除并返回指定键的值。shift
方法删除哈希中的第一个键值对。它还以数组的形式返回已删除的键值对。
names.delete 4
在这里,我们删除一个键值对 4 => "Julia"
。
names.shift
此代码行删除第一个键值对,即 1 => "Jane"
。
$ ./delete_items.rb {2=>"Thomas", 3=>"Robert", 5=>"Rebecca"}
在输出中,我们可以看到哈希中剩余的键值对。
reject
和 delete_if
方法可以从哈希中删除多个键值对。这些方法删除在块中对给定条件返回 true 的键值对。这两种方法之间存在一个重要的区别。reject
方法在哈希的副本上工作,而 delete_if
方法在原始哈希上工作。
#!/usr/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 的键值对。该方法修改了原始哈希。
$ ./delete_if.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"}
Ruby 向哈希添加元素
Ruby 的 merge 和 update 方法将 (key, value) 对添加到哈希中。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 names = names1.update names2 puts names
在 Ruby 脚本中,我们创建了两个哈希。然后我们在它们上应用 merge
和 update
方法。
names = names1.merge names2 puts names
names1 和 names2 哈希合并。结果分配给 names 哈希。我们打印新创建的哈希。
$ ./adding.rb {1=>"Jane", 2=>"Thomas", 3=>"Robert", 4=>"Julia"} {1=>"Jane", 2=>"Thomas", 3=>"Robert", 4=>"Julia"}
正如我们所看到的,最终的哈希包含来自 names1
和 names2
哈希的键值对。
Ruby 哈希的 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
我们在 merge
和 merge!
方法上演示了区别。
names = names1.merge names2
merge
不会修改 names1
哈希。它在它的副本上工作。
names = names1.merge! names2
merge!
方法在原始哈希上工作。names1
哈希被更改。
$ ./merging.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"}
在本章中,我们学习了 Ruby 哈希。