1. 什么是哈希?
哈希是一个无序的键值对集合,用 {}
定义。键是唯一的,值可以重复。哈希通过键快速访问对应的值。
基本定义
person = { "name" => "张三", "age" => 25 }
puts person # {"name"=>"张三", "age"=>25}
符号键(推荐)
使用符号作为键更简洁:
person = { name: "张三", age: 25 }
puts person # {:name=>"张三", :age=>25}
其他定义方式
# 空哈希
empty = {}
# 多行定义
student = {
name: "李四",
grade: "A",
age: 20
}
2. 访问哈希元素
通过键
person = { name: "张三", age: 25 }
puts person[:name] # 张三
puts person[:age] # 25
puts person[:city] # nil(键不存在返回 nil)
使用 fetch
指定默认值或抛出异常:
puts person.fetch(:name) # 张三
puts person.fetch(:city, "未知") # 未知
# puts person.fetch(:city) # 抛出 KeyError
3. 修改哈希
添加或更新
person = { name: "张三" }
person[:age] = 25 # 添加
person[:name] = "李四" # 更新
puts person # {:name=>"李四", :age=>25}
删除
delete
person = { name: "张三", age: 25 }
person.delete(:age)
puts person # {:name=>"张三"}
clear
person.clear
puts person # {}
合并
merge
hash1 = { name: "张三" }
hash2 = { age: 25, city: "北京" }
combined = hash1.merge(hash2)
puts combined # {:name=>"张三", :age=>25, :city=>"北京"}
merge!
(破坏性)
hash1.merge!(hash2)
puts hash1 # {:name=>"张三", :age=>25, :city=>"北京"}
4. 常用方法
长度与状态
person = { name: "张三", age: 25 }
puts person.length # 2
puts person.size # 2(同 length)
puts person.empty? # false
puts person.key?(:name) # true
遍历
each
person.each do |key, value|
puts "#{key}: #{value}"
end
输出:
name: 张三
age: 25
each_key
person.each_key { |k| puts k } # name, age
each_value
person.each_value { |v| puts v } # 张三, 25
获取键和值
puts person.keys # [:name, :age]
puts person.values # ["张三", 25]
转换
to_a
puts person.to_a # [[:name, "张三"], [:age, 25]]
invert
puts person.invert # {"张三"=>:name, 25=>:age}
过滤
select
filtered = person.select { |k, v| v.is_a?(Integer) }
puts filtered # {:age=>25}
reject
filtered = person.reject { |k, v| v.is_a?(String) }
puts filtered # {:age=>25}
5. 默认值
设置默认值
counts = Hash.new(0) # 未定义的键返回 0
counts[:apples] += 1
counts[:oranges] += 2
puts counts # {:apples=>1, :oranges=>2}
puts counts[:bananas] # 0
用块设置动态默认值
time_hash = Hash.new { |hash, key| hash[key] = Time.now }
puts time_hash[:start] # 当前时间
6. 中文支持示例
处理中文哈希
学生 = { 姓名: "王五", 年龄: 20, 城市: "上海" }
学生.each do |键, 值|
puts "#{键}:#{值}"
end
输出:
姓名:王五
年龄:20
城市:上海
实践案例
class Student
def initialize(info)
@info = info
end
def display
@info.map { |k, v| "#{k}:#{v}" }.join("\n")
end
end
学生 = Student.new({ 姓名: "赵六", 年级: "A" })
puts 学生.display
输出:
姓名:赵六
年级:A
7. 哈希的不可变性与修改
普通方法
大多数方法返回新哈希,不修改原哈希:
person = { name: "张三", age: 25 }
filtered = person.select { |k, v| v.is_a?(String) }
puts person # {:name=>"张三", :age=>25}
puts filtered # {:name=>"张三"}
破坏性方法(带 !
)
修改原哈希:
person = { name: "张三", age: 25, city: "北京" }
person.delete_if! { |k, v| v.is_a?(Integer) }
puts person # {:name=>"张三", :city=>"北京"}
8. 实践案例
案例 1:成绩统计
grades = { "张三" => 85, "李四" => 92, "王五" => 78 }
average = grades.values.sum / grades.length.to_f
puts "平均分:#{average}" # 平均分:85.0
案例 2:购物车
cart = { 手机: 2000, 耳机: 150 }
cart[:充电器] = 50
total = cart.values.sum
puts "总价:#{total} 元" # 总价:2200 元
案例 3:计数器
counts = Hash.new(0)
"你好你好世界".chars.each { |char| counts[char] += 1 }
puts counts # {"你"=>2, "好"=>2, "世"=>1, "界"=>1}
9. 注意事项
- 键唯一性:重复的键会覆盖旧值:
hash = { a: 1, a: 2 }
puts hash # {:a=>2}
- 性能:哈希查找是 O(1),非常高效。
- 符号 vs 字符串:符号键更节省内存,推荐使用。
下一步
- 练习:告诉我你想用哈希做什么(遍历、过滤等),我可以设计一个例子。
- 问题解答:对哈希用法有疑问吗?直接问我!
- 深入学习:想了解哈希与数组的嵌套或性能优化吗?我可以继续讲解。
你现在想做什么?写代码、问问题,还是其他?
发表回复