Ruby 的哈希

本章节我们学习另外一个可以组合多个的对象类——哈希,了解哈希是什么,如何创建一个哈希以及哈希对象的实例方法。

1. 什么是哈希

哈希是键值对的集合。—— 官方定义

哈希是另一种非常有用且广泛使用的东西,可用于存储其他对象。与仅作为列表的数组不同,哈希表就像字典。我们通过键(key)来查找哈希中的值(value)。好比我们有一个英汉词典,我们通过查找“hello的单词来找到中文意思"你好",此时,“hello“就是作为键,而“你好”就是值。

我们将哈希的每一对键和值称为键值对,每一个哈希可以拥有任意数量的键值对。

2. 如何创建一个哈希

与数组一样,哈希有很多创建方法,我们可以通过哈希所属 Hash 类中的new方法来创建一个空的哈希。

实例:

> Hash.new
=> {}

我们也可以在创建哈希的时候为它赋予初始值:

实例:

> H = Hash["a" => 100, "b" => 200]
=> {"a"=>100, "b"=>200}

在 Ruby 中,我们通过使用=>将键分配给值来创建哈希,用逗号分隔多个键值对,并用花括号将整个内容括起来。

实例:

> a = { "one" => "1", "two" => "2", "three" => "3" }
=> {"one"=>"1", "two"=>"2", "three"=>"3"}

解释:这是一个定义了3个键值对的哈希,我们可以通过 one,来找到 1,通过 two 来找到 2,也可以通过three 来找到 3。

我们更多使用标志对象(Symbol)或者字符串对象(String)来作为哈希的键。不过我们记住一点:哈希的键和值可以是任意类型的对象

实例:

{ 1 => "eins", 2 => "zwei", 3 => "drei" }
{ :one => "eins", :two => "zwei", :three => "drei" }
{ "weights" => ["pound", "kilogram"], "lengths" => ["meter", "mile"] }
{ :de => { :one => "eins", :two => "zwei", :three => "drei" } }

解释:

  • 第一个实例使用数字类型作为键,第二个则使用标志类型作为键;

  • 第三个实例我们看到它的值是一个数组;

  • 第四个示例我们得到一个嵌套的哈希,在哈希中我们还可以将键对应的值设置成另一个哈希。

Tips : 关于格式化:请注意,两侧的花括号内,=>周围以及每个逗号后都有一个空格。

经验:

标志对象(Symbol)作为键时,我们会经常使用一个新的写法,而不是使用火箭(=>),这种写法更贴近与 JSON 的写法。

实例:

{ one: "eins", two: "zwei", three: "drei" }

# 与这种方法创建哈希是等价的
{ :one => "eins", :two => "zwei", :three => "drei" }

这种写法会让 Ruby 将键解释为 Symbol。

3. 哈希的实例方法

3.1 查找值

我们使用[]方法,通过传入键来查找对应的值。

实例:

# 定义一个哈希
dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
puts dictionary["one"]

# ---- 输出结果 ----
"eins"

当我们查找的键没有对应内容时,会返回一个nil

实例:

puts dictionary["four"]

# ---- 输出结果 ----
nil

另外我们很少会用到一个fetch方法,他和[]方法一样都可以查找某一个键的值,但是如果键对应的值不存在,会抛出异常。

实例:

puts dictionary.fetch("one")

# ---- 输出结果 ----
"eins
puts dictionary.fetch("four")

# ---- 输出结果 ----
KeyError (key not found: "four")

3.2 更改某一个键对应的值

使用[]=方法,传入键与更改的值:

实例:

# 定义一个哈希
dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
# 更改one对应的值
dictionary["one"] = "uno"
puts dictionary

# ---- 输出结果 ----
{"one"=>"uno", "two"=>"zwei", "three"=>"drei"}

您还可以通过这种方法为哈希增加键值对:

实例:

dictionary["zero"] = "null"
puts dictionary

# ---- 输出结果 ----
{"one"=>"null", "two"=>"zwei", "three"=>"drei", "zero"=>"null"}

3.3 合并两个哈希

使用merge方法。

实例:

a = { "one" => "eins" }
b = { "two" => "zwei" }
puts a.merge(b)
puts a 

# ---- 输出结果 ----
{"one"=>"eins", "two"=>"zwei"}
{"one" => "eins"}

Tips : merge!方法会在合并的同时,将结果赋值给原有的哈希,而merge方法不会改变原有的哈希。

实例:

a = { "one" => "eins" }
b = { "two" => "zwei" }
puts a.merge(b)
puts a

# ---- 输出结果 ----
{"one"=>"eins", "two"=>"zwei"}
{"one"=>"eins", "two"=>"zwei"}

3.4 获得哈希拥有的所有键

keys返回一个带有哈希知道的所有键的数组:

实例:

# 定义一个哈希
dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
dictionary.keys

# ---- 输出结果 ----
["one", "two", "three"]

3.5 获得哈希拥有的所有值

values返回一个带有哈希所有值的数组:

# 定义一个哈希
dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
dictionary.values

# ---- 输出结果 ----
["eins", "zwei", "drei"]

3.6 判断是不是空哈希

使用empty?

实例:

{}.empty?

# ---- 输出结果 ----
true

或者使用size或者length方法,判断哈希的大小是否为0。

实例:

dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
puts dictionary.size == 0
puts dictionary.length == 0

# ---- 输出结果 ----
false
false

3.7 删除一个键值对

通过delete,并传入要删除的键作为参数。

dictionary = { "one" => "eins", "two" => "zwei", "three" => "drei" }
dictionary.delete("one")
puts dictionary

# ---- 输出结果 ----
{"two"=>"zwei", "three"=>"drei"}

如果键不存在,则不会进行操作。

4. 小结

本章中我们学习了如何创建一个哈希,通过哈希如何查找值、替换值、增加值,合并哈希、删除键值对、获得哈希键或值的数组、判断是否为空。