Ruby哈希 #

一、哈希概述 #

哈希是Ruby中的键值对集合,类似于其他语言中的字典或关联数组。哈希的键可以是任意对象,但通常使用符号或字符串。

ruby
hash = { name: "Ruby", version: 3.3 }
hash.class
hash.length

二、创建哈希 #

2.1 字面量语法 #

ruby
hash = {}
hash = { "name" => "Ruby", "version" => 3.3 }
hash = { name: "Ruby", version: 3.3 }
hash = { :name => "Ruby", :version => 3.3 }
hash = { "name" => "Ruby", age: 30 }

2.2 Hash方法 #

ruby
Hash.new
Hash.new("default")
Hash.new { |h, k| h[k] = [] }
Hash[]
Hash[a: 1, b: 2]
Hash[[[:a, 1], [:b, 2]]]
Hash["a", 1, "b", 2]

2.3 其他创建方式 #

ruby
[[:a, 1], [:b, 2]].to_h
[[:a, 1], [:b, 2]].each_with_object({}) { |(k, v), h| h[k] = v }
Array.new(3) { |i| [i, i * 2] }.to_h
(1..3).map { |i| [i, i ** 2] }.to_h

三、哈希访问 #

3.1 键访问 #

ruby
hash = { name: "Ruby", version: 3.3 }

hash[:name]
hash["name"]
hash[:nonexistent]
hash[:nonexistent] || "default"
hash.fetch(:name)
hash.fetch(:nonexistent, "default")
hash.fetch(:nonexistent) { |k| "#{k} not found" }

3.2 dig方法 #

ruby
hash = { user: { profile: { name: "Ruby" } } }

hash.dig(:user, :profile, :name)
hash.dig(:user, :settings, :theme)
hash[:user]&.[](:profile)&.[](:name)

3.3 values_at #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.values_at(:a, :b)
hash.values_at(:a, :d)
hash.fetch_values(:a, :b)
hash.fetch_values(:a, :d) { |k| "#{k} missing" }

3.4 slice #

ruby
hash = { a: 1, b: 2, c: 3, d: 4 }

hash.slice(:a, :b)
hash.slice(:a, :e)
hash.except(:a, :b)

四、哈希修改 #

4.1 添加/修改元素 #

ruby
hash = { a: 1 }

hash[:b] = 2
hash.store(:c, 3)
hash.merge!({ d: 4, e: 5 })
hash.replace({ x: 1, y: 2 })

4.2 删除元素 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.delete(:a)
hash.delete(:nonexistent)
hash.delete(:nonexistent) { |k| "#{k} not found" }
hash.delete_if { |k, v| v > 1 }
hash.reject! { |k, v| v > 1 }
hash.keep_if { |k, v| v > 1 }
hash.select! { |k, v| v > 1 }
hash.compact!
hash.transform_values! { |v| v * 2 }
hash.clear

4.3 shift #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.shift
hash.shift

五、哈希查询 #

5.1 键查询 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.key?(:a)
hash.has_key?(:a)
hash.include?(:a)
hash.member?(:a)
hash.keys
hash.key(1)

5.2 值查询 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.value?(1)
hash.has_value?(1)
hash.values
hash.value?(10)

5.3 空检查 #

ruby
hash = {}

hash.empty?
hash.nil?
hash.length
hash.size
hash.count
hash.count { |k, v| v > 1 }

六、哈希遍历 #

6.1 each遍历 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.each { |k, v| puts "#{k}: #{v}" }
hash.each_key { |k| puts k }
hash.each_value { |v| puts v }
hash.each_pair { |k, v| puts "#{k}: #{v}" }

6.2 map转换 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.map { |k, v| [k, v * 2] }.to_h
hash.transform_values { |v| v * 2 }
hash.transform_keys { |k| k.to_s }
hash.transform_keys(&:to_s)
hash.transform_keys!(&:to_s)
hash.transform_values! { |v| v * 2 }

6.3 select过滤 #

ruby
hash = { a: 1, b: 2, c: 3, d: 4 }

hash.select { |k, v| v.even? }
hash.reject { |k, v| v.even? }
hash.filter { |k, v| v > 2 }
hash.select! { |k, v| v.even? }

6.4 reduce聚合 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.reduce(0) { |sum, (k, v)| sum + v }
hash.reduce({}) { |h, (k, v)| h[k.to_s] = v; h }
hash.each_with_object([]) { |(k, v), arr| arr << "#{k}=#{v}" }

七、哈希合并 #

7.1 merge #

ruby
h1 = { a: 1, b: 2 }
h2 = { b: 3, c: 4 }

h1.merge(h2)
h1.merge(h2) { |k, v1, v2| v1 + v2 }
h1.merge!(h2)
h1.reverse_merge(h2)

7.2 合并策略 #

ruby
h1 = { a: 1, b: 2 }
h2 = { b: 3, c: 4 }

h1.merge(h2)
h2.merge(h1)
h1.merge(h2) { |k, old, new| old }
h1.merge(h2) { |k, old, new| new }
h1.merge(h2) { |k, old, new| old + new }

八、哈希转换 #

8.1 转数组 #

ruby
hash = { a: 1, b: 2, c: 3 }

hash.to_a
hash.to_s
hash.inspect
hash.flatten
hash.keys
hash.values
hash.to_h

8.2 键值互换 #

ruby
hash = { a: 1, b: 2, c: 1 }

hash.invert
hash.invert.invert

8.3 转JSON #

ruby
require 'json'

hash = { name: "Ruby", version: 3.3 }
hash.to_json
JSON.generate(hash)
JSON.parse(hash.to_json)

九、默认值 #

9.1 默认值设置 #

ruby
hash = Hash.new(0)
hash[:a] += 1
hash[:a]
hash[:b]

hash = Hash.new { |h, k| h[k] = [] }
hash[:a] << 1
hash[:a]
hash[:b]

9.2 默认值方法 #

ruby
hash = { a: 1 }

hash.default
hash.default = 0
hash.default_proc
hash.default_proc = proc { |h, k| h[k] = [] }

9.3 常见陷阱 #

ruby
hash = Hash.new([])
hash[:a] << 1
hash[:b]
hash[:a].object_id == hash[:b].object_id

hash = Hash.new { |h, k| h[k] = [] }
hash[:a] << 1
hash[:b]

十、哈希排序 #

10.1 按键排序 #

ruby
hash = { c: 3, a: 1, b: 2 }

hash.sort
hash.sort.to_h
hash.keys.sort
hash.sort_by { |k, v| k }

10.2 按值排序 #

ruby
hash = { a: 3, b: 1, c: 2 }

hash.sort_by { |k, v| v }
hash.sort_by { |k, v| v }.to_h
hash.sort_by { |k, v| -v }.to_h
hash.sort_by(&:last).to_h

十一、嵌套哈希 #

11.1 创建嵌套哈希 #

ruby
hash = {
  user: {
    name: "Ruby",
    profile: {
      age: 30,
      city: "Beijing"
    }
  }
}

hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
hash[:a][:b][:c] = 1

11.2 访问嵌套哈希 #

ruby
hash = { user: { profile: { name: "Ruby" } } }

hash[:user][:profile][:name]
hash.dig(:user, :profile, :name)
hash.dig(:user, :settings, :theme)
hash.fetch(:user).fetch(:profile).fetch(:name)

11.3 深度合并 #

ruby
def deep_merge(h1, h2)
  h1.merge(h2) do |k, v1, v2|
    if v1.is_a?(Hash) && v2.is_a?(Hash)
      deep_merge(v1, v2)
    else
      v2
    end
  end
end

h1 = { a: { b: 1, c: 2 } }
h2 = { a: { c: 3, d: 4 } }
deep_merge(h1, h2)

十二、实用示例 #

12.1 计数器 #

ruby
def word_count(text)
  text.split.each_with_object(Hash.new(0)) { |word, hash| hash[word] += 1 }
end

word_count("hello world hello ruby world")

12.2 分组 #

ruby
def group_by_key(items, key)
  items.group_by { |item| item[key] }
end

users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 25 }
]

group_by_key(users, :age)

12.3 哈希路径访问 #

ruby
class HashPath
  def self.get(hash, path)
    keys = path.to_s.split(".")
    keys.reduce(hash) { |h, k| h&.[](k.to_sym) || h&.[](k) }
  end

  def self.set(hash, path, value)
    keys = path.to_s.split(".")
    last_key = keys.pop
    target = keys.reduce(hash) { |h, k| h[k.to_sym] ||= {} }
    target[last_key.to_sym] = value
    hash
  end
end

data = { user: { profile: { name: "Ruby" } } }
HashPath.get(data, "user.profile.name")
HashPath.set(data, "user.profile.age", 30)

12.4 哈希差异 #

ruby
def hash_diff(h1, h2)
  keys = (h1.keys | h2.keys)
  keys.each_with_object({}) do |key, diff|
    if h1[key] != h2[key]
      diff[key] = { old: h1[key], new: h2[key] }
    end
  end
end

hash_diff({ a: 1, b: 2 }, { a: 1, b: 3, c: 4 })

12.5 哈希符号化键 #

ruby
def symbolize_keys(hash)
  hash.transform_keys { |k| k.to_sym rescue k }
end

def deep_symbolize_keys(hash)
  hash.transform_keys(&:to_sym).transform_values do |v|
    v.is_a?(Hash) ? deep_symbolize_keys(v) : v
  end
end

symbolize_keys({ "name" => "Ruby", "age" => 30 })
deep_symbolize_keys({ "user" => { "name" => "Ruby" } })

十三、总结 #

本章我们学习了:

  1. 创建哈希:字面量、Hash.new、to_h
  2. 哈希访问:[]、fetch、dig、values_at
  3. 哈希修改:添加、删除、合并
  4. 哈希查询:key?、value?、keys、values
  5. 哈希遍历:each、map、select、reduce
  6. 默认值:Hash.new、default_proc
  7. 嵌套哈希:创建、访问、深度合并

接下来让我们学习Ruby的范围!

最后更新:2026-03-27