本文简要介绍ruby语言中 Hash类
的用法。
哈希将其每个唯一键映射到特定值。
Hash 与 Array 有某些相似之处,但是:
-
数组索引始终是整数。
-
哈希键可以(几乎)是任何对象。
哈希数据语法
哈希数据的旧语法使用“哈希火箭”=>
:
h = {:foo => 0, :bar => 1, :baz => 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
或者,但仅对于作为符号的哈希键,您可以使用更新的 JSON-style 语法,其中每个裸词都成为符号:
h = {foo: 0, bar: 1, baz: 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
您还可以使用字符串代替裸词:
h = {'foo': 0, 'bar': 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
您可以混合样式:
h = {foo: 0, :bar => 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
但是尝试 JSON-style 语法来获取不是裸词或字符串的键是错误的:
# Raises SyntaxError (syntax error, unexpected ':', expecting =>): h = {0: 'zero'}
Hash
值可以省略,这意味着该值将通过键的名称从上下文中获取:
x = 0
y = 100
h = {x:, y:}
h # => {:x=>0, :y=>100}
常见用途
您可以使用 Hash 为对象命名:
person = {name: 'Matz', language: 'Ruby'}
person # => {:name=>"Matz", :language=>"Ruby"}
您可以使用 Hash 为方法参数命名:
def some_method(hash)
p hash
end
some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2}
注意:当方法调用的最后一个参数是 Hash 时,可以省略花括号:
some_method(foo: 0, bar: 1, baz: 2) # => {:foo=>0, :bar=>1, :baz=>2}
您可以使用哈希来初始化对象:
class Dev
attr_accessor :name, :language
def initialize(hash)
self.name = hash[:name]
self.language = hash[:language]
end
end
matz = Dev.new(name: 'Matz', language: 'Ruby')
matz # => #<Dev: @name="Matz", @language="Ruby">
创建哈希
您可以使用以下命令显式创建 Hash 对象:
-
一个hash literal。
您可以使用以下方法将某些对象转换为哈希:
-
方法Hash。
您可以通过调用方法 Hash.new
创建一个哈希。
创建一个空哈希:
h = Hash.new
h # => {}
h.class # => Hash
您可以通过调用方法 Hash.[]
创建一个哈希。
创建一个空哈希:
h = Hash[]
h # => {}
创建一个带有初始条目的哈希:
h = Hash[foo: 0, bar: 1, baz: 2]
h # => {:foo=>0, :bar=>1, :baz=>2}
您可以使用其文字形式(大括号)创建一个 Hash。
创建一个空哈希:
h = {}
h # => {}
创建一个带有初始条目的哈希:
h = {foo: 0, bar: 1, baz: 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
哈希值基础
检索哈希值的最简单方法(实例方法 []
):
h = {foo: 0, bar: 1, baz: 2}
h[:foo] # => 0
创建或更新哈希值的最简单方法(实例方法 []=
):
h = {foo: 0, bar: 1, baz: 2}
h[:bat] = 3 # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
h[:foo] = 4 # => 4
h # => {:foo=>4, :bar=>1, :baz=>2, :bat=>3}
删除哈希条目的最简单方法(实例方法 delete
):
h = {foo: 0, bar: 1, baz: 2}
h.delete(:bar) # => 1
h # => {:foo=>0, :baz=>2}
入场令
Hash 对象按其创建顺序显示其条目。这可见于:
-
迭代方法,例如
each
、each_key
、each_pair
、each_value
。 -
其他顺序敏感的方法,例如
shift
、keys
、values
。 -
方法
inspect
返回的字符串。
根据给定条目,新哈希具有其初始排序:
h = Hash[foo: 0, bar: 1]
h # => {:foo=>0, :bar=>1}
最后添加新条目:
h[:baz] = 2
h # => {:foo=>0, :bar=>1, :baz=>2}
更新值不会影响顺序:
h[:baz] = 3
h # => {:foo=>0, :bar=>1, :baz=>3}
但是重新创建已删除的条目可能会影响顺序:
h.delete(:foo)
h[:foo] = 5
h # => {:bar=>1, :baz=>3, :foo=>5}
哈希键
哈希键等价
当两个对象的hash
值相同并且两个对象彼此为eql?
时,两个对象被视为相同的哈希键。
修改活动哈希键
在使用时修改哈希键会损坏哈希的索引。
此哈希具有数组键:
a0 = [ :foo, :bar ]
a1 = [ :baz, :bat ]
h = {a0 => 0, a1 => 1}
h.include?(a0) # => true
h[a0] # => 0
a0.hash # => 110002110
修改数组元素a0[0]
会改变其哈希值:
a0[0] = :bam
a0.hash # => 1069447059
并损坏哈希索引:
h.include?(a0) # => false
h[a0] # => nil
您可以使用方法 rehash
修复哈希索引:
h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1}
h.include?(a0) # => true
h[a0] # => 0
字符串键始终是安全的。这是因为作为键传递的未冻结字符串将被重复和冻结的字符串替换:
s = 'foo'
s.frozen? # => false
h = {s => 0}
first_key = h.keys.first
first_key.frozen? # => true
用户定义的哈希键
要用作哈希键,对象必须实现方法 hash
和 eql?
。注意:如果哈希使用 compare_by_identity
,则此要求不适用,因为比较将依赖于键的对象 id 而不是 hash
和 eql?
。
Object 定义了hash
和eq?
的基本实现,使每个对象成为不同的键。通常,用户定义的类将希望覆盖这些方法以提供有意义的行为,或者例如继承对这些具有有用定义的 Struct。
hash
的典型实现基于对象的数据,而 eql?
通常别名为重写的 ==
方法:
class Book
attr_reader :author, :title
def initialize(author, title)
@author = author
@title = title
end
def ==(other)
self.class === other &&
other.author == @author &&
other.title == @title
end
alias eql? ==
def hash
@author.hash ^ @title.hash # XOR
end
end
book1 = Book.new 'matz', 'Ruby in a Nutshell'
book2 = Book.new 'matz', 'Ruby in a Nutshell'
reviews = {}
reviews[book1] = 'Great reference!'
reviews[book2] = 'Nice and compact!'
reviews.length #=> 1
默认值
[]
、 values_at
和 dig
方法需要返回与某个键关联的值。当未找到该键时,该值将由其默认 proc(如果有)或默认值(最初为“nil”)确定。
您可以使用方法 default
检索默认值:
h = Hash.new
h.default # => nil
您可以通过将参数传递给方法 Hash.new
或使用方法 default=
来设置默认值
h = Hash.new(-1)
h.default # => -1
h.default = 0
h.default # => 0
当未找到 key 时,将为 []
、 values_at
和 dig
返回此默认值:
counts = {foo: 42}
counts.default # => nil (default)
counts[:foo] = 42
counts[:bar] # => nil
counts.default = 0
counts[:bar] # => 0
counts.values_at(:foo, :bar, :baz) # => [42, 0, 0]
counts.dig(:bar) # => 0
请注意,使用默认值而不重复。不建议将默认值设置为可变对象:
synonyms = Hash.new([])
synonyms[:hello] # => []
synonyms[:hello] << :hi # => [:hi], but this mutates the default!
synonyms.default # => [:hi]
synonyms[:world] << :universe
synonyms[:world] # => [:hi, :universe], oops
synonyms.keys # => [], oops
要将可变对象用作默认值,建议使用默认 proc
默认过程
当设置了 Hash 的默认 proc 时(即不是 nil
),方法 []
返回的默认值仅由默认 proc 确定。
您可以使用方法 default_proc
检索默认过程:
h = Hash.new
h.default_proc # => nil
您可以通过使用块调用 Hash.new
或调用方法 default_proc=
来设置默认过程
h = Hash.new { |hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
h.default_proc = proc { |hash, key| "Default value for #{key.inspect}" }
h.default_proc.class # => Proc
当设置了默认过程(即不是 nil
)并且使用不存在的键调用方法 []
时, []
使用 Hash 对象本身和缺少的键调用默认过程,然后返回proc的返回值:
h = Hash.new { |hash, key| "Default value for #{key}" }
h[:nosuch] # => "Default value for nosuch"
请注意,在上面的示例中,没有为键 :nosuch
创建条目:
h.include?(:nosuch) # => false
但是,proc 本身可以添加一个新条目:
synonyms = Hash.new { |hash, key| hash[key] = [] }
synonyms.include?(:hello) # => false
synonyms[:hello] << :hi # => [:hi]
synonyms[:world] << :universe # => [:universe]
synonyms.keys # => [:hello, :world]
请注意,设置默认 proc 将清除默认值,反之亦然。
这里有什么
首先,其他地方有什么。类哈希:
-
继承自 class Object 。
-
包括 module Enumerable ,它提供了许多附加方法。
在这里,类 Hash 提供了有用的方法:
类 Hash 还包括来自模块 Enumerable
的方法。
创建哈希的方法
- Hash[]
-
返回用给定对象填充的新哈希。
- Hash.new
-
返回一个新的空哈希。
::try_convert
-
返回从给定对象创建的新哈希。
设置哈希状态的方法
- Hash.compare_by_identity
-
设置
self
以在比较键时仅考虑身份。 - Hash.default =
-
将默认值设置为给定值。
- Hash.default_proc =
-
将默认 proc 设置为给定的 proc。
rehash
-
通过重新计算每个键的哈希索引来重建哈希表。
查询方法
- Hash.any?
-
返回是否有任何元素满足给定条件。
compare_by_identity?
-
返回比较键时哈希是否只考虑身份。
- Hash.default
-
返回默认值,或给定键的默认值。
- Hash.default_proc
-
返回默认过程。
- Hash.empty?
-
返回是否没有条目。
- Hash.eql? object
-
返回给定对象是否等于
self
。 - Hash.hash
-
返回整数哈希码。
has_value?
-
返回给定对象是否是
self
中的值。 -
include?
,has_key?
,member?
,key?
-
返回给定对象是否是
self
中的键。 -
length
,size
-
返回条目数。
value?
-
返回给定对象是否是
self
中的值。
比较方法
- #
-
返回
self
是否是给定对象的真子集。 - #
-
返回
self
是否是给定对象的子集。 - #==
-
返回给定对象是否等于
self
。 - #>
-
返回
self
是否是给定对象的正确超集 - #>=
-
返回
self
是否是给定对象的正确超集。
获取方法
- Hash.hash[key]
-
返回与给定键关联的值。
- Hash.assoc
-
返回包含给定键及其值的 2 元素数组。
- Hash.dig
-
返回由给定键和附加参数指定的嵌套对象中的对象。
- Hash.fetch
-
返回给定键的值。
- Hash.fetch_values
-
返回包含与给定键关联的值的数组。
- Hash.key
-
返回具有给定值的first-found 条目的键。
- Hash.keys
-
返回包含
self
中所有键的数组。 - Hash.rassoc
-
返回一个 2 元素数组,该数组由具有给定值的 first-found 条目的键和值组成。
- Hash.values
-
返回一个包含
self
中所有值的数组/ - Hash.values_at
-
返回一个包含给定键值的数组。
分配方法
-
[]=
,store
-
将给定键与给定值相关联。
- Hash.merge
-
返回通过将每个给定哈希合并到
self
的副本中形成的哈希。 -
merge!
,update
-
将每个给定的哈希合并到
self
中。 - Hash.replace
-
将
self
的全部内容替换为 givan 哈希的内容。
删除方法
这些方法从 self
中删除条目:
clear
-
从
self
中删除所有条目。 - Hash.compact!
-
从
self
中删除所有nil
值条目。 - Hash.delete
-
删除给定键的条目。
- Hash.delete_if
-
删除给定块选择的条目。
-
filter!
,select!
-
仅保留给定块选择的那些条目。
- Hash.keep_if
-
仅保留给定块选择的那些条目。
- Hash.reject!
-
删除给定块选择的条目。
- Hash.shift
-
删除并返回第一个条目。
这些方法返回 self
的副本,其中删除了一些条目:
- Hash.compact
-
返回
self
的副本,其中删除了所有nil
值条目。 - Hash.except
-
返回
self
的副本,其中删除了指定键的条目。 -
filter
,select
-
返回
self
的副本,其中仅包含给定块选择的条目。 - Hash.reject
-
返回
self
的副本,其中删除了给定块指定的条目。 - Hash.slice
-
返回包含给定键的条目的哈希。
迭代方法
-
each
,each_pair
-
使用每个键值对调用给定块。
- Hash.each_key
-
使用每个键调用给定的块。
- Hash.each_value
-
使用每个值调用给定块。
转换方法
-
inspect
,to_s
-
返回包含哈希条目的新
String
。 - Hash.to_a
-
返回一个新的 2 元素数组;每个嵌套数组都包含一个来自
self
的键值对。 - Hash.to_h
-
如果是哈希,则返回
self
;如果是 Hash 的子类,则返回包含来自self
的条目的 Hash。 to_hash
-
返回
self
。 - Hash.to_proc
-
返回一个将给定键映射到其值的过程。
转换键和值的方法
- Hash.transform_keys
-
返回带有修改键的
self
的副本。 transform_keys!
-
修改
self
中的键 - Hash.transform_values
-
返回带有修改值的
self
的副本。 - Hash.transform_values!
-
修改
self
中的值。
其他方法
- Hash.flatten
-
返回一个数组,它是
self
的一维展平。 - Hash.invert
-
返回每个键值对反转的哈希。
相关用法
- Ruby Hash.reject用法及代码示例
- Ruby Hash shift()用法及代码示例
- Ruby Hash.delete()用法及代码示例
- Ruby Hash length()用法及代码示例
- Ruby Hash.new用法及代码示例
- Ruby Hash.size用法及代码示例
- Ruby Hash rehash用法及代码示例
- Ruby Hash.delete用法及代码示例
- Ruby Hash.hash <=用法及代码示例
- Ruby Hash size()用法及代码示例
- Ruby Hash each_pair()用法及代码示例
- Ruby Hash.select!用法及代码示例
- Ruby Hash value?用法及代码示例
- Ruby Hash values用法及代码示例
- Ruby Hash.ruby2_keywords_hash用法及代码示例
- Ruby Hash.rassoc(obj)用法及代码示例
- Ruby Hash.to_s用法及代码示例
- Ruby Hash.values_at()用法及代码示例
- Ruby Hash.fetch_values()用法及代码示例
- Ruby Hash.select用法及代码示例
- Ruby Hash.initialize_copy用法及代码示例
- Ruby Hash.replace用法及代码示例
- Ruby Hash member?用法及代码示例
- Ruby Hash each_key用法及代码示例
- Ruby Hash dig()用法及代码示例
注:本文由纯净天空筛选整理自ruby-lang.org大神的英文原创作品 Hash类。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。