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 字符串:符号键更节省内存,推荐使用。

下一步

  • 练习:告诉我你想用哈希做什么(遍历、过滤等),我可以设计一个例子。
  • 问题解答:对哈希用法有疑问吗?直接问我!
  • 深入学习:想了解哈希与数组的嵌套或性能优化吗?我可以继续讲解。

你现在想做什么?写代码、问问题,还是其他?