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。
- 13:
h(13) = 13 % 5 = 3,所以 Hash[3] = 13。 - 7:
h(7) = 7 % 5 = 2,所以 Hash[2] = 7。 - 14:
h(14) = 14 % 5 = 4,所以 Hash[4] = 14。 - 11:
h(11) = 11 % 5 = 1,所以 Hash[1] = 11。
现在查找 11 是否存在。
如果用数组,你需要用一个 for 循环遍历 4 次。用 Hash 时,只要先计算 h(11) = 11 % 5 = 1,再直接看 Hash[1] 是不是 11 就可以了,只查 1 次。
这就是 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 的 keys 和 values 方法返回的都是数组,所以可以直接用数组的方法处理它们:
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]
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 使用RVM切换Ruby与Rails版本的实现方法
- 时间:2026-08-18
-
- Ruby语言是什么及入门使用方法
- 时间:2026-08-18
-
- Ruby on Rails网站项目搭建入门指南
- 时间:2026-08-18
-
- Ruby插入排序算法实现与二路插入排序代码示例
- 时间:2026-08-18
-
- Ruby图片滤镜算法实现代码与核心原理
- 时间:2026-08-18
-
- Ruby面向对象编程:类方法与类扩展详解
- 时间:2026-08-18
-
- Ruby正则表达式语法详解与常用示例代码
- 时间:2026-08-18
-
- Ruby二分搜索算法简单实现与查找示例
- 时间:2026-08-18
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
