Skip to content

Ruby 哈希

在 Ruby 中,哈希 (Hash) 是一种由键值对(key-value pairs)组成的集合,也称为关联数组(associative array)或字典(dictionary)。它类似于数组(Array),但索引使用的是任意键(任意对象类型),而非整数索引。

从 Ruby 1.9 版本开始,哈希会保持插入顺序(insertion order)。当你遍历(iterate)一个哈希时,键值对会按照它们最初插入的顺序被取出。如果你尝试用一个不存在的键访问哈希,通常会返回 nil(除非指定了默认值 default value 或 块 block)。

有几种创建哈希的方式:

// 1. 使用哈希字面量语法(最常用)
empty_hash = {}
name_to_age = { "Alice" => 30, "Bob" => 25, "Charlie" => 35 }
// 2. 对 Symbol 键使用新的“无火箭”语法 (Ruby 1.9+)
// 这非常常见,特别是用于关键字参数。
symbol_keyed_hash = { name: "David", age: 40, city: "New York" }
// 等同于:{ :name => "David", :age => 40, :city => "New York" }
// 3. 使用 Hash.new 创建一个空哈希
months = Hash.new
// 4. 使用 Hash.new 设置默认值(用于不存在的键)
default_value_hash = Hash.new(0) # 访问缺失的键会返回 0
puts default_value_hash["non_existent_key"] # => 0
// 5. 使用 Hash.new 配合块 (block) 动态计算默认值
// 每次访问未知键时,都会执行该块。
dynamic_default_hash = Hash.new { |hash, key| hash[key] = "Default for #{key}" }
puts dynamic_default_hash["first_try"] # => "Default for first_try"
puts dynamic_default_hash["first_try"] # 现在它存在了,所以返回存储的值。
puts dynamic_default_hash.inspect # => {"first_try"=>"Default for first_try"}
// 6. 使用 Hash[] 类方法(作为字面量不太常用)
coordinates = Hash[:x, 10, :y, 20, :z, 5]
// 等同于:{ :x => 10, :y => 20, :z => 5 }

哈希中的键(Keys)和值(values)可以是任何对象类型。但是,键必须是唯一的(unique)。如果你为一个已存在的键赋值,旧的值将被覆盖。

常见键类型:Symbol (:my_key) 常被优先用作键,因为它们是不可变(immutable)且内存效率高的。字符串(String,"my_key")也很常见。

哈希拥有一系列丰富的方法用于操作。假设 my_hash 是一个哈希对象 (Hash object):

#!/usr/bin/env ruby
# frozen_string_literal: true
months = { "1" => "January", "2" => "February", "3" => "March" }
# 获取所有键
keys = months.keys
puts "Keys: #{keys.inspect}" # 输出: Keys: ["1", "2", "3"]
# 获取所有值
values = months.values
puts "Values: #{values.inspect}" # 输出: Values: ["January", "February", "March"]
# 遍历键值对
months.each do |key, value|
puts "Month number #{key} is #{value}"
end

以下是一些常见的公共哈希方法 (Hash methods)。有关完整列表,请参阅官方 Ruby 文档。

ID方法及描述
1hash == other_hash
测试两个哈希是否相等:拥有相同的键值对数量,且每个键值对都相等(使用 == 进行比较)。
2hash[key]
访问与 key 关联的值。如果找不到键,返回 nil 或默认值/块的执行结果。
3hash[key] = value
将 value 与 key 关联。如果键已存在,则覆盖现有值。别名:store。
4hash.clear
从 hash 中移除所有键值对,使其变为空。
5hash.default(key = nil)
返回 hash 的默认值(如果找不到 key,则 hash[key] 会返回该值)。
6hash.default = obj
设置访问哈希中不存在的键时返回的默认值。
7hash.default_proc
如果 hash 是使用默认块创建的,则返回该块;否则返回 nil。
8hash.delete(key) 或 hash.delete(key) { |k| block_value }
删除由 key 指定的键值对。返回与该键关联的值。如果找不到该键,则返回 nil;如果提供了块,则执行该块并返回其结果。
9hash.delete_if { |key, value| block_condition }
删除块评估结果为 true 的键值对。返回哈希本身。别名 reject!(破坏性)。
10hash.each { |key, value| block } 或 hash.each_pair { |key, value| block }
遍历哈希,将每个键值对传递给块。如果没有提供块,则返回一个 Enumerator。
11hash.each_key { |key| block }
遍历哈希,将每个键传递给块。如果没有提供块,则返回一个 Enumerator。
12hash.each_value { |value| block }
遍历哈希,将每个值传递给块。如果没有提供块,则返回一个 Enumerator。
13hash.empty?
如果哈希不包含任何键值对,则返回 true。
14hash.fetch(key [, default_value]) 或 hash.fetch(key) { |k| block_value }
返回 key 对应的值。如果找不到 key,则抛出 KeyError。如果提供了 default_value,则返回该值。如果提供了块,则返回块的执行结果。
15hash.key?(key) 或 hash.has_key?(key) 或 hash.include?(key) 或 hash.member?(key)
如果哈希中存在给定的 key,则返回 true。
16hash.value?(value) 或 hash.has_value?(value)
如果哈希中存在给定的 value,则返回 true。
17hash.key(value)
返回给定 value 首次出现的对应键。如果没有找到匹配的值,则返回 nil。
18hash.invert
返回一个新哈希,该哈希由 hash 中的键和值反转创建。如果存在重复的值,将选择其中一个对应的键作为新的值(选择哪个键的行为可能因 Ruby 版本或实现而异)。
19hash.keys
返回一个新数组,包含 hash 中的所有键。
20hash.length 或 hash.size
返回哈希中键值对的数量,为一个整数。
21hash.merge(other_hash) 或 hash.merge(other_hash) { |key, old_val, new_val| block_value }
返回一个包含 hash 和 other_hash 内容的新哈希。如果同一个键在两个哈希中都存在,默认使用 other_hash 中的值;如果提供了块,则使用块的结果来解决冲突。
22hash.merge!(other_hash) 或 hash.merge!(other_hash) { |key, old_val, new_val| block_value }
与 merge 相同,但会直接修改 hash。别名:update。
23hash.rehash
根据每个键当前的哈希值重建哈希。当可变键(mutable keys)自插入以来其哈希值发生改变时需要使用。
24hash.reject { |key, value| block_condition }
返回一个新哈希,其中只包含块评估结果为 false 或 nil 的键值对。
25hash.reject! { |key, value| block_condition }
与 reject 相同,但会直接修改 hash。如果未进行任何更改,则返回 hash;否则返回 nil。
26hash.replace(other_hash)
将 hash 的内容替换为 other_hash 的内容。
27hash.select { |key, value| block_condition }
返回一个新哈希,其中只包含块评估结果为 true 的键值对。
28hash.select! { |key, value| block_condition }
与 select 相同,但会直接修改 hash。如果未进行任何更改,则返回 hash;否则返回 nil。
29hash.shift
从 hash 中移除第一个键值对(根据插入顺序),并将其作为包含两个元素的数组 [key, value] 返回。如果哈希为空,则返回 nil 或默认值。
30hash.slice(*keys)
返回一个新哈希,其中只包含指定 keys 对应的键值对 (Ruby 2.5+)。
31hash.transform_keys { |key| new_key }
返回一个新哈希,其键由块转换。
32hash.transform_keys! { |key| new_key }
与 transform_keys 相同,但会直接修改 hash。
33hash.transform_values { |value| new_value }
返回一个新哈希,其值由块转换。
34hash.transform_values! { |value| new_value }
与 transform_values 相同,但会直接修改 hash。
35hash.sort 或 hash.sort { |(k1,v1), (k2,v2)| block_comparison }
将 hash 转换为 [key, value] 对的嵌套数组并进行排序。默认按键排序。可以提供一个块用于自定义排序逻辑。
36hash.to_a
将 hash 转换为嵌套数组,其中每个内部数组都是一个 [key, value] 对。
37hash.to_h 或 hash.to_hash
返回 self(哈希本身)。对于转换实现了 to_h 方法的类数组对象很有用。
38hash.to_s 或 hash.inspect
返回哈希的字符串表示,通常适用于打印或调试。
39hash.values
返回一个新数组,包含 hash 中的所有值。
40hash.values_at(key1, key2, …)
返回一个新数组,包含与给定键关联的值。如果找不到某个键,则在该数组位置使用 nil(或默认值)。