位置:首页 > Ruby > Ruby中Hash哈希结构基本操作方法详解

Ruby中Hash哈希结构基本操作方法详解

时间:2026-08-18  |  作者:骑光打字机  |  阅读:0

哈希(Hash)是编程中绕不开的核心概念之一。很多人刚接触时觉得它高深,其实本质上就是一种“映射”思路,用来提升数据查找效率。

下面从最基础的原理讲起,再深入到 Ruby 中 Hash 的具体实现和常用操作。整个过程尽量用通俗方式拆解,帮助你快速上手。

关于哈希

先看 Hash 的基本思路。

假设我们要存储 num 个对象,就用 len 个内存单元来存放它们,其中 len >= num。每个对象 ki 都有一个关键字,我们设计一个函数 h(ki),把关键字映射成内存地址,也就是下标。

然后,把对象内容存到这个地址里。这就是 Hash 的核心逻辑。

Hash 的关键作用是:用固定规则把数据映射到某个位置,再按同样规则快速找到它。

为什么要用函数来映射地址?下面用一个简单例子说明。

假设现在要存储 4 个元素:13、7、14、11。

当然,用数组也能存:a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;

但 Hash 的做法不同。我们定义一个简单的映射函数:h(ki) = ki % 5

  • 13h(13) = 13 % 5 = 3,所以 Hash[3] = 13。
  • 7h(7) = 7 % 5 = 2,所以 Hash[2] = 7。
  • 14h(14) = 14 % 5 = 4,所以 Hash[4] = 14。
  • 11h(11) = 11 % 5 = 1,所以 Hash[1] = 11。

现在查找 11 是否存在。

如果用数组,你需要用一个 for 循环遍历 4 次。用 Hash 时,只要先计算 h(11) = 11 % 5 = 1,再直接看 Hash[1] 是不是 11 就可以了,只查 1 次。

这就是 Hash 的精妙之处:通过映射函数直接定位数据,大幅提升查找效率。

Ruby中Hash哈希结构的基本操作方法小结

Ruby 中的 Hash 结构

1. 创建哈希

和创建数组一样,我们可以通过 Hash 类创建实例:

h1 = Hash.new                         # 默认值为 nil
h2 = Hash.new("This is my first hash instance") # 默认值为 "This is my first hash instance"

上面两个例子都创建了一个空的 Hash 实例。

每个 Hash 对象都有一个默认值。如果在一个 Hash 对象里没有找到指定的索引(key),就会返回这个默认值。

创建 Hash 对象后,就可以像数组那样添加或删除项。

不同的是,数组的索引只能是整数,而 Hash 的索引(key)可以是任何类型的数据,并且必须唯一:

h2["one"] = "北京"
h2["two"] = "上海"
h2["three"] = "深圳"
h2["four"] = "广州"

注意:如果赋值时使用了相同的 key,后面的值会覆盖前面的值。

Ruby 还提供了更方便的创建和初始化方式。写法是在 key 后面加 =>,每组 key-value 对之间用逗号分隔,整体用大括号括起来:

h2 = {
  "one" => "北京",
  "two" => "上海",
  "three" => "深圳",
  "four" => "广州"
}

2. 通过索引存取 Hash 的值

获取某个值,可以这样写:

puts h2["one"]       # => "北京"

如果指定的 key 不存在,就会返回默认值。

此外,还可以用 default 方法获取默认值,用 default= 方法设置新的默认值:

puts h1.default
h1.default = "This is set value method"

3. 复制 Hash

和数组一样,把一个 Hash 变量赋给另一个变量时,两个变量会引用同一个 Hash。

因此,修改其中一个,另一个也会跟着变化:

h3 = h2
h3["one"] = "西安"
puts h2["one"]        # => "西安"

如果不希望这样,可以使用 clone 方法创建一个真正的副本:

h4 = h2.clone
h4["one"] = "大连"
puts h2["one"]        # => "西安"(值没有修改)

4. Hash 排序

Hash 不能直接按普通数组的方式理解排序。

因为数组里的数据类型通常一致,比如都是整数;而 Hash 里的 key 类型可能混在一起,比如整数和字符串,这两类值无法直接比较。

处理方式如下:

def sorted_hash(aHash)
  return aHash.sort{ |a,b| a.to_s <=> b.to_s }
end

h1 = {1=>'one', 2=>'two', 3=>'three'}
h2 = {6=>'six', 5=>'five', 4=>'four'}
h3 = {'one'=>'A', 'two'=>'B', 'three'=>'C'}
h4 = h1.merge(h2)           # 合并 hash
h5 = h1.merge(h3)

p(h4)          
p(h4.sort)
p(h5)
p(sorted_hash(h5))

运行结果:

{5=>"five", 6=>"six", 1=>"one", 2=>"two", 3=>"three", 4=>"four"}
[[1, "one"], [2, "two"], [3, "three"], [4, "four"], [5, "five"], [6, "six"]]
{"two"=>"B", "three"=>"C", 1=>"one", 2=>"two", "one"=>"A", 3=>"three"}
[[1, "one"], [2, "two"], [3, "three"], ["one", "A"], ["three", "C"], ["two", "B"]]

事实上,Hash 的 sort 方法会先把 Hash 对象转换成由 [key, value] 组成的数组,再用数组的 sort 方法进行排序。

5. Hash 类常用方法

方法

说明

size()

返回 Hash 对象的长度

length()

返回 Hash 对象的长度

include(key)

判断指定的 Hash 对象是否包含指定的 key

has_key(key)

判断指定的 Hash 对象是否包含指定的 key

delete(key)

删除 Hash 对象中指定 key 的对应元素

keys()

返回由 Hash 对象中全部 key 组成的数组

values()

返回由 Hash 对象中全部 value 组成的数组

举个例子:

student = {
  "name" => "Steve",
  "age" => 22,
  "Gender" => "male"
}

p student.keys                           # => ["name", "Gender", "age"]
p student.values                         # => ["Steve", "male", 22]
puts student.include?("age")             # => true
puts student.size                        # => 3
student.delete("Gender")
puts student.has_key?("Gender")           # => false
puts student.size                        # => 2

深度挖掘

1. 把 Hash 当作数组来处理

Hash 的 keysvalues 方法返回的都是数组,所以可以直接用数组的方法处理它们:

h1 = {1=>'one', 2=>'two', 3=>'three', 4=>'four'}
h2 = {1=>'one', 3=>'two', 4=>'four', 5=>'five'}

p( h1.keys & h2.keys )       # 交集
p( h1.values & h2.values )
p( h1.keys + h2.keys )       # 并集
p( h1.values - h2.values )   # 差集
p( (h1.keys << h2.keys) )   # 追加
p( (h1.keys << h2.keys).flatten )

结果:

[1, 3, 4]
["one", "two", "four"]
[1, 2, 3, 4, 5, 1, 3, 4]
["three"]
[1, 2, 3, 4, [5, 1, 3, 4]]
[1, 2, 3, 4, 5, 1, 3, 4]

2. 追加和连续的区别

+ 给数组添加元素时,会创建一个新的数组。

<< 则是直接操作原数组。如果新添加的元素本身也是数组,它会作为最后一个元素整体加入。

a = [1, 2, 3]
b = [4, 5, 6]

p(a + b)
p(a << b)

结果:

[1, 2, 3, 4, 5, 6]
[1, 2, 3, [4, 5, 6]]     # 注意:a << b 后 a 变成了 [1,2,3,[4,5,6]],再调用 .flatten 才能得到 [1,2,3,4,5,6]

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多