类哈希
哈希将它的每个唯一键映射到特定值。
哈希与 数组
有某些相似之处,但
哈希数据语法¶ ↑
哈希数据的旧语法使用“哈希火箭”=>
h = {:foo => 0, :bar => 1, :baz => 2} h # => {:foo=>0, :bar=>1, :baz=>2}
或者,仅对哈希键是 Symbol
的情况,可以使用较新的 JSON 风格语法,其中每个裸字都将成为一个 Symbol
h = {foo: 0, bar: 1, baz: 2} h # => {:foo=>0, :bar=>1, :baz=>2}
您还可以使用 String
代替裸字
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}
但尝试对不是裸字或 String 的键使用 JSON 风格语法会出错
# Raises SyntaxError (syntax error, unexpected ':', expecting =>): h = {0: 'zero'}
Hash
值可以省略,这意味着该值将通过键的名称从上下文中获取
x = 0 y = 100 h = {x:, y:} h # => {:x=>0, :y=>100}
常见用法¶ ↑
您可以使用哈希为对象指定名称
person = {name: 'Matz', language: 'Ruby'} person # => {:name=>"Matz", :language=>"Ruby"}
您可以使用哈希为方法参数指定名称
def some_method(hash) p hash end some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2}
注意:当方法调用中的最后一个参数是哈希时,可以省略大括号
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.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}
您可以使用其文字形式(大括号)来创建哈希。
创建空哈希
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}
项顺序¶ ↑
哈希对象按创建顺序显示其项。这在以下内容中可见
-
迭代方法,例如
each
、each_key
、each_pair
、each_value
。 -
其他对顺序敏感的方法,如
shift
、keys
、values
。 -
方法
inspect
返回的String
。
新哈希的初始排序顺序由给定的条目决定
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
一个 String
键始终是安全的。这是因为作为键传递的未冻结 String
将被复制并冻结的 String 替换
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 [self.class, @author, @title].hash 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
需要返回与特定键关联的值。当找不到该键时,该值将由其默认过程(如果有)或其默认值(最初为“nil”)确定。
可以使用方法 default
检索默认值
h = Hash.new h.default # => nil
可以通过向方法 Hash.new
传递参数或使用方法 default=
设置默认值
h = Hash.new(-1) h.default # => -1 h.default = 0 h.default # => 0
当找不到键时,此默认值将为 []
、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 的默认过程(即不为 nil
)时,方法 []
返回的默认值仅由默认过程决定。
您可以使用 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 对象本身和丢失的键调用默认过程,然后返回过程的返回值
h = Hash.new { |hash, key| "Default value for #{key}" } h[:nosuch] # => "Default value for nosuch"
请注意,在上面的示例中,不会创建键 :nosuch
的条目
h.include?(:nosuch) # => false
但是,过程本身可以添加新条目
synonyms = Hash.new { |hash, key| hash[key] = [] } synonyms.include?(:hello) # => false synonyms[:hello] << :hi # => [:hi] synonyms[:world] << :universe # => [:universe] synonyms.keys # => [:hello, :world]
请注意,设置默认过程会清除默认值,反之亦然。
请注意,修改哈希的默认过程在多线程调用同一个键的默认过程时不是线程安全的。
此处内容¶ ↑
首先,其他地方的内容。类 Hash
-
继承自 类 Object。
-
包括 模块 Enumerable,它提供了数十个其他方法。
此处,类 Hash 提供了对以下内容有用的方法
类 Hash 还包括来自模块 Enumerable
的方法。
创建 Hash 的方法¶ ↑
-
::[]
:返回一个填充有给定对象的新哈希。 -
::new
:返回一个新的空哈希。 -
::try_convert
:返回一个从给定对象创建的新哈希。
设置哈希状态的方法¶ ↑
-
compare_by_identity
:设置self
以仅在比较键时考虑标识。 -
default=
:将默认值设置为给定值。 -
default_proc=
:将默认过程设置为给定过程。 -
rehash
:通过重新计算每个键的哈希索引来重建哈希表。
查询方法¶ ↑
-
any?
:返回任何元素是否满足给定条件。 -
compare_by_identity?
:返回哈希在比较键时是否仅考虑标识。 -
default
:返回默认值或给定键的默认值。 -
default_proc
:返回默认过程。 -
empty?
:返回是否存在条目。 -
eql?
:返回给定对象是否等于self
。 -
hash
:返回整数哈希代码。 -
has_value?
:返回给定对象是否为self
中的值。 -
value?
:返回给定对象是否为self
中的值。
比较方法¶ ↑
-
<
:返回self
是否是给定对象的真子集。 -
<=
:返回self
是否是给定对象的子集。 -
==
:返回给定对象是否等于self
。 -
>
:返回self
是否是给定对象的真超集 -
>=
:返回self
是否是给定对象的超集。
获取方法¶ ↑
-
[]
:返回与给定键关联的值。 -
assoc
:返回一个包含给定键及其值的 2 元素数组。 -
dig
:返回嵌套对象中由给定键和附加参数指定的对象。 -
fetch
:返回给定键的值。 -
fetch_values
:返回包含与给定键关联的值的数组。 -
key
:返回具有给定值的第一个找到的条目的键。 -
keys
:返回包含self
中所有键的数组。 -
rassoc
:返回一个包含具有给定值的第一条目的键和值的 2 元素数组。 -
values
:返回包含self
中所有值的数组/ -
values_at
:返回包含给定键值的数组。
分配方法¶ ↑
删除方法¶ ↑
这些方法从 self
中移除条目
-
clear
:从self
中移除所有条目。 -
compact!
:从self
中移除所有值为nil
的条目。 -
delete
:移除给定键的条目。 -
delete_if
:移除由给定块选中的条目。 -
keep_if
:仅保留由给定块选中的那些条目。 -
reject!
:移除由给定块选中的条目。 -
shift
:移除并返回第一个条目。
这些方法返回 self
的副本,其中已移除一些条目
-
compact
:返回self
的副本,其中已移除所有值为nil
的条目。 -
except
:返回self
的副本,其中已移除指定键的条目。 -
reject
:返回self
的副本,其中已移除由给定块指定的条目。 -
slice
:返回包含给定键的条目的哈希。
迭代方法¶ ↑
-
each_key
:使用每个键调用给定的块。 -
each_value
:使用每个值调用给定的块。
转换方法¶ ↑
-
to_a
:返回一个由 2 元素数组组成的新数组;每个嵌套数组包含来自self
的键值对。 -
to_h
:如果为哈希,则返回self
;如果为哈希的子类,则返回一个包含来自self
的条目的哈希。 -
to_hash
:返回self
。 -
to_proc
:返回一个将给定键映射到其值的 proc。
转换键和值的方法¶ ↑
-
transform_keys
:返回修改后的键的self
副本。 -
transform_keys!
:修改self
中的键 -
transform_values
:返回修改后的值的self
副本。 -
transform_values!
:修改self
中的值。
其他方法¶ ↑
公共类方法
如果提供任何对象,则返回一个填充了给定对象的新 Hash 对象。请参阅 Hash::new
。
如果没有参数,则返回一个新的空 Hash。
当给定的单个参数是 Hash 时,返回一个新的 Hash,其中填充了给定 Hash 中的条目,不包括默认值或过程。
h = {foo: 0, bar: 1, baz: 2} Hash[h] # => {:foo=>0, :bar=>1, :baz=>2}
当给定的单个参数是 2 元素数组的 Array
时,返回一个新的 Hash 对象,其中每个 2 元素数组形成一个键值条目
Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {:foo=>0, :bar=>1}
当参数计数为偶数时;返回一个新的 Hash 对象,其中每对连续参数都已成为一个键值条目
Hash[:foo, 0, :bar, 1] # => {:foo=>0, :bar=>1}
如果参数列表不符合上述任何条件,则引发异常。
static VALUE rb_hash_s_create(int argc, VALUE *argv, VALUE klass) { VALUE hash, tmp; if (argc == 1) { tmp = rb_hash_s_try_convert(Qnil, argv[0]); if (!NIL_P(tmp)) { if (!RHASH_EMPTY_P(tmp) && rb_hash_compare_by_id_p(tmp)) { /* hash_copy for non-empty hash will copy compare_by_identity flag, but we don't want it copied. Work around by converting hash to flattened array and using that. */ tmp = rb_hash_to_a(tmp); } else { hash = hash_alloc(klass); if (!RHASH_EMPTY_P(tmp)) hash_copy(hash, tmp); return hash; } } else { tmp = rb_check_array_type(argv[0]); } if (!NIL_P(tmp)) { long i; hash = hash_alloc(klass); for (i = 0; i < RARRAY_LEN(tmp); ++i) { VALUE e = RARRAY_AREF(tmp, i); VALUE v = rb_check_array_type(e); VALUE key, val = Qnil; if (NIL_P(v)) { rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)", rb_builtin_class_name(e), i); } switch (RARRAY_LEN(v)) { default: rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)", RARRAY_LEN(v)); case 2: val = RARRAY_AREF(v, 1); case 1: key = RARRAY_AREF(v, 0); rb_hash_aset(hash, key, val); } } return hash; } } if (argc % 2 != 0) { rb_raise(rb_eArgError, "odd number of arguments for Hash"); } hash = hash_alloc(klass); rb_hash_bulk_insert(argc, argv, hash); hash_verify(hash); return hash; }
返回一个新的空 Hash 对象。
新哈希的初始默认值和初始默认过程取决于上面使用了哪种形式。请参阅 默认值。
如果没有给定参数或块,则将默认值和默认过程都初始化为 nil
h = Hash.new h.default # => nil h.default_proc # => nil
如果给定了参数 default_value
但没有给定块,则将默认值初始化为给定的 default_value
,将默认过程初始化为 nil
h = Hash.new(false) h.default # => false h.default_proc # => nil
如果给定了块但没有给定参数,则将块存储为默认过程,并将默认值设置为 nil
h = Hash.new {|hash, key| "Default value for #{key}" } h.default # => nil h.default_proc.class # => Proc h[:nosuch] # => "Default value for nosuch"
static VALUE rb_hash_initialize(int argc, VALUE *argv, VALUE hash) { rb_hash_modify(hash); if (rb_block_given_p()) { rb_check_arity(argc, 0, 0); SET_PROC_DEFAULT(hash, rb_block_proc()); } else { rb_check_arity(argc, 0, 1); VALUE options, ifnone; rb_scan_args(argc, argv, "01:", &ifnone, &options); if (NIL_P(ifnone) && !NIL_P(options)) { ifnone = options; rb_warn_deprecated_to_remove("3.4", "Calling Hash.new with keyword arguments", "Hash.new({ key: value })"); } RHASH_SET_IFNONE(hash, ifnone); } return hash; }
复制给定哈希并添加 ruby2_keywords 标记。此方法不适用于一般用途;调试、研究以及一些真正必要的情况,例如参数反序列化。
h = {k: 1} h = Hash.ruby2_keywords_hash(h) def foo(k: 42) k end foo(*[h]) #=> 1 with neither a warning or an error
static VALUE rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash) { Check_Type(hash, T_HASH); VALUE tmp = rb_hash_dup(hash); if (RHASH_EMPTY_P(hash) && rb_hash_compare_by_id_p(hash)) { rb_hash_compare_by_id(tmp); } RHASH(tmp)->basic.flags |= RHASH_PASS_AS_KEYWORDS; return tmp; }
检查给定哈希是否被 Module#ruby2_keywords
(或 Proc#ruby2_keywords
)标记。此方法不适用于一般用途;调试、研究以及一些真正必要的情况,例如参数序列化。
ruby2_keywords def foo(*args) Hash.ruby2_keywords_hash?(args.last) end foo(k: 1) #=> true foo({k: 1}) #=> false
static VALUE rb_hash_s_ruby2_keywords_hash_p(VALUE dummy, VALUE hash) { Check_Type(hash, T_HASH); return RBOOL(RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS); }
如果 obj
是 Hash 对象,则返回 obj
。
否则,如果 obj
响应 :to_hash
,则调用 obj.to_hash
并返回结果。
如果 obj
不响应 :to_hash
,则返回 nil
除非 obj.to_hash
返回 Hash 对象,否则引发异常。
static VALUE rb_hash_s_try_convert(VALUE dummy, VALUE hash) { return rb_check_hash_type(hash); }
公共实例方法
如果 hash
是 other_hash
的真子集,则返回 true
,否则返回 false
h1 = {foo: 0, bar: 1} h2 = {foo: 0, bar: 1, baz: 2} h1 < h2 # => true h2 < h1 # => false h1 < h1 # => false
static VALUE rb_hash_lt(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) >= RHASH_SIZE(other)) return Qfalse; return hash_le(hash, other); }
如果 hash
是 other_hash
的子集,则返回 true
,否则返回 false
h1 = {foo: 0, bar: 1} h2 = {foo: 0, bar: 1, baz: 2} h1 <= h2 # => true h2 <= h1 # => false h1 <= h1 # => true
static VALUE rb_hash_le(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) > RHASH_SIZE(other)) return Qfalse; return hash_le(hash, other); }
如果满足以下所有条件,则返回 true
-
object
是 Hash 对象。 -
hash
和object
具有相同的键(与顺序无关)。 -
对于每个键
key
,hash[key] == object[key]
。
否则,返回 false
。
相等
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1, baz: 2} h1 == h2 # => true h3 = {baz: 2, bar: 1, foo: 0} h1 == h3 # => true
static VALUE rb_hash_equal(VALUE hash1, VALUE hash2) { return hash_equal(hash1, hash2, FALSE); }
如果 hash
是 other_hash
的真超集,则返回 true
,否则返回 false
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1} h1 > h2 # => true h2 > h1 # => false h1 > h1 # => false
static VALUE rb_hash_gt(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) <= RHASH_SIZE(other)) return Qfalse; return hash_le(other, hash); }
如果 hash
是 other_hash
的超集,则返回 true
,否则返回 false
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1} h1 >= h2 # => true h2 >= h1 # => false h1 >= h1 # => true
static VALUE rb_hash_ge(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) < RHASH_SIZE(other)) return Qfalse; return hash_le(other, hash); }
如果找到,则返回与给定 key
关联的值
h = {foo: 0, bar: 1, baz: 2} h[:foo] # => 0
如果未找到 key
,则返回默认值(请参阅 默认值)
h = {foo: 0, bar: 1, baz: 2} h[:nosuch] # => nil
VALUE rb_hash_aref(VALUE hash, VALUE key) { st_data_t val; if (hash_stlike_lookup(hash, key, &val)) { return (VALUE)val; } else { return rb_hash_default_value(hash, key); } }
将给定的值
与给定的键
关联;返回值
。
如果给定的键
存在,则用给定的值
替换其值;顺序不受影响(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:foo] = 2 # => 2 h.store(:bar, 3) # => 3 h # => {:foo=>2, :bar=>3}
如果键
不存在,则添加键
和值
;新条目按顺序排列在最后(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:baz] = 2 # => 2 h.store(:bat, 3) # => 3 h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val) { bool iter_p = hash_iterating_p(hash); rb_hash_modify(hash); if (RHASH_TYPE(hash) == &identhash || rb_obj_class(key) != rb_cString) { RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val); } else { RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val); } return val; }
如果任何元素满足给定的条件,则返回true
;否则返回false
。
如果self
没有元素,则返回false
,并且不使用参数或块。
如果没有参数和块,如果self
非空,则返回true
;如果为空,则返回false
。
带有参数object
且没有块,如果对于任何键key
h.assoc(key) == object
,则返回true
h = {foo: 0, bar: 1, baz: 2} h.any?([:bar, 1]) # => true h.any?([:bar, 0]) # => false h.any?([:baz, 1]) # => false
如果没有参数且有块,则用每个键值对调用块;如果块返回任何真值,则返回true
,否则返回false
h = {foo: 0, bar: 1, baz: 2} h.any? {|key, value| value < 3 } # => true h.any? {|key, value| value > 3 } # => false
static VALUE rb_hash_any_p(int argc, VALUE *argv, VALUE hash) { VALUE args[2]; args[0] = Qfalse; rb_check_arity(argc, 0, 1); if (RHASH_EMPTY_P(hash)) return Qfalse; if (argc) { if (rb_block_given_p()) { rb_warn("given block not used"); } args[1] = argv[0]; rb_hash_foreach(hash, any_p_i_pattern, (VALUE)args); } else { if (!rb_block_given_p()) { /* yields pairs, never false */ return Qtrue; } if (rb_block_pair_yield_optimizable()) rb_hash_foreach(hash, any_p_i_fast, (VALUE)args); else rb_hash_foreach(hash, any_p_i, (VALUE)args); } return args[0]; }
如果找到给定的键
,则返回一个包含该键及其值的 2 元素数组
h = {foo: 0, bar: 1, baz: 2} h.assoc(:bar) # => [:bar, 1]
如果找不到键键
,则返回nil
。
static VALUE rb_hash_assoc(VALUE hash, VALUE key) { VALUE args[2]; if (RHASH_EMPTY_P(hash)) return Qnil; if (RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type != &identhash) { VALUE value = Qundef; st_table assoctable = *RHASH_ST_TABLE(hash); assoctable.type = &(struct st_hash_type){ .compare = assoc_cmp, .hash = assoctable.type->hash, }; VALUE arg = (VALUE)&(struct assoc_arg){ .tbl = &assoctable, .key = (st_data_t)key, }; if (RB_OBJ_FROZEN(hash)) { value = assoc_lookup(arg); } else { hash_iter_lev_inc(hash); value = rb_ensure(assoc_lookup, arg, hash_foreach_ensure, hash); } hash_verify(hash); if (!UNDEF_P(value)) return rb_assoc_new(key, value); } args[0] = key; args[1] = Qnil; rb_hash_foreach(hash, assoc_i, (VALUE)args); return args[1]; }
删除所有哈希表条目;返回self
。
VALUE rb_hash_clear(VALUE hash) { rb_hash_modify_check(hash); if (hash_iterating_p(hash)) { rb_hash_foreach(hash, clear_i, 0); } else if (RHASH_AR_TABLE_P(hash)) { ar_clear(hash); } else { st_clear(RHASH_ST_TABLE(hash)); compact_after_delete(hash); } return hash; }
返回一个self
的副本,其中删除了所有nil
值条目
h = {foo: 0, bar: nil, baz: 2, bat: nil} h1 = h.compact h1 # => {:foo=>0, :baz=>2}
static VALUE rb_hash_compact(VALUE hash) { VALUE result = rb_hash_dup(hash); if (!RHASH_EMPTY_P(hash)) { rb_hash_foreach(result, delete_if_nil, result); compact_after_delete(result); } else if (rb_hash_compare_by_id_p(hash)) { result = rb_hash_compare_by_id(result); } return result; }
返回self
,其中所有nil
值条目已删除(就地)
h = {foo: 0, bar: nil, baz: 2, bat: nil} h.compact! # => {:foo=>0, :baz=>2}
如果没有删除任何条目,则返回 nil
。
static VALUE rb_hash_compact_bang(VALUE hash) { st_index_t n; rb_hash_modify_check(hash); n = RHASH_SIZE(hash); if (n) { rb_hash_foreach(hash, delete_if_nil, hash); if (n != RHASH_SIZE(hash)) return hash; } return Qnil; }
设置 self
以仅在比较键时考虑标识;只有当两个键是同一对象时,才认为它们相同;返回 self
。
默认情况下,这两个对象被认为是同一个键,因此 s1
将覆盖 s0
s0 = 'x' s1 = 'x' h = {} h.compare_by_identity? # => false h[s0] = 0 h[s1] = 1 h # => {"x"=>1}
在调用 #compare_by_identity 之后,这些键被认为是不同的,因此不会相互覆盖
h = {} h.compare_by_identity # => {} h.compare_by_identity? # => true h[s0] = 0 h[s1] = 1 h # => {"x"=>0, "x"=>1}
VALUE rb_hash_compare_by_id(VALUE hash) { VALUE tmp; st_table *identtable; if (rb_hash_compare_by_id_p(hash)) return hash; rb_hash_modify_check(hash); if (hash_iterating_p(hash)) { rb_raise(rb_eRuntimeError, "compare_by_identity during iteration"); } if (RHASH_TABLE_EMPTY_P(hash)) { // Fast path: There's nothing to rehash, so we don't need a `tmp` table. // We're most likely an AR table, so this will need an allocation. ar_force_convert_table(hash, __FILE__, __LINE__); HASH_ASSERT(RHASH_ST_TABLE_P(hash)); RHASH_ST_TABLE(hash)->type = &identhash; } else { // Slow path: Need to rehash the members of `self` into a new // `tmp` table using the new `identhash` compare/hash functions. tmp = hash_alloc(0); hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash)); identtable = RHASH_ST_TABLE(tmp); rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); rb_hash_free(hash); // We know for sure `identtable` is an st table, // so we can skip `ar_force_convert_table` here. RHASH_ST_TABLE_SET(hash, identtable); RHASH_ST_CLEAR(tmp); } return hash; }
如果已调用 compare_by_identity
,则返回 true
,否则返回 false
。
VALUE rb_hash_compare_by_id_p(VALUE hash) { return RBOOL(RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type == &identhash); }
返回给定 key
的默认值。返回值将由默认过程或默认值确定。请参阅 默认值。
如果没有参数,则返回当前默认值
h = {} h.default # => nil
如果给出了 key
,则返回 key
的默认值,无论该键是否存在
h = Hash.new { |hash, key| hash[key] = "No key #{key}"} h[:foo] = "Hello" h.default(:foo) # => "No key foo"
static VALUE rb_hash_default(int argc, VALUE *argv, VALUE hash) { VALUE ifnone; rb_check_arity(argc, 0, 1); ifnone = RHASH_IFNONE(hash); if (FL_TEST(hash, RHASH_PROC_DEFAULT)) { if (argc == 0) return Qnil; return call_default_proc(ifnone, hash, argv[0]); } return ifnone; }
将默认值设置为 value
;返回 value
h = {} h.default # => nil h.default = false # => false h.default # => false
请参阅 默认值。
static VALUE rb_hash_set_default(VALUE hash, VALUE ifnone) { rb_hash_modify_check(hash); SET_DEFAULT(hash, ifnone); return ifnone; }
返回 self
的默认过程(请参阅 默认值)
h = {} h.default_proc # => nil h.default_proc = proc {|hash, key| "Default value for #{key}" } h.default_proc.class # => Proc
static VALUE rb_hash_default_proc(VALUE hash) { if (FL_TEST(hash, RHASH_PROC_DEFAULT)) { return RHASH_IFNONE(hash); } return Qnil; }
将 self
的默认过程设置为 proc
:(请参阅 默认值)
h = {} h.default_proc # => nil h.default_proc = proc { |hash, key| "Default value for #{key}" } h.default_proc.class # => Proc h.default_proc = nil h.default_proc # => nil
VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc) { VALUE b; rb_hash_modify_check(hash); if (NIL_P(proc)) { SET_DEFAULT(hash, proc); return proc; } b = rb_check_convert_type_with_id(proc, T_DATA, "Proc", idTo_proc); if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, "wrong default_proc type %s (expected Proc)", rb_obj_classname(proc)); } proc = b; SET_PROC_DEFAULT(hash, proc); return proc; }
删除给定 key
的条目并返回其关联值。
如果未给出块并且找到了 key
,则删除该条目并返回关联值
h = {foo: 0, bar: 1, baz: 2} h.delete(:bar) # => 1 h # => {:foo=>0, :baz=>2}
如果未给出块并且未找到 key
,则返回 nil
。
如果给出了块并且找到了 key
,则忽略该块,删除该条目并返回关联值
h = {foo: 0, bar: 1, baz: 2} h.delete(:baz) { |key| raise 'Will never happen'} # => 2 h # => {:foo=>0, :bar=>1}
如果给出了块并且未找到 key
,则调用该块并返回该块的返回值
h = {foo: 0, bar: 1, baz: 2} h.delete(:nosuch) { |key| "Key #{key} not found" } # => "Key nosuch not found" h # => {:foo=>0, :bar=>1, :baz=>2}
static VALUE rb_hash_delete_m(VALUE hash, VALUE key) { VALUE val; rb_hash_modify_check(hash); val = rb_hash_delete_entry(hash, key); if (!UNDEF_P(val)) { compact_after_delete(hash); return val; } else { if (rb_block_given_p()) { return rb_yield(key); } else { return Qnil; } } }
如果给出了块,则使用每个键值对调用该块;删除块返回真值的所有条目;返回 self
h = {foo: 0, bar: 1, baz: 2} h.delete_if {|key, value| value > 0 } # => {:foo=>0}
如果未给出块,则返回一个新的枚举器
h = {foo: 0, bar: 1, baz: 2} e = h.delete_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:delete_if> e.each { |key, value| value > 0 } # => {:foo=>0}
VALUE rb_hash_delete_if(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { rb_hash_foreach(hash, delete_if_i, hash); compact_after_delete(hash); } return hash; }
查找并返回嵌套对象中由 key
和 identifiers
指定的对象。嵌套对象可能是各种类的实例。请参阅 Dig 方法。
嵌套哈希
h = {foo: {bar: {baz: 2}}} h.dig(:foo) # => {:bar=>{:baz=>2}} h.dig(:foo, :bar) # => {:baz=>2} h.dig(:foo, :bar, :baz) # => 2 h.dig(:foo, :bar, :BAZ) # => nil
嵌套哈希和数组
h = {foo: {bar: [:a, :b, :c]}} h.dig(:foo, :bar, 2) # => :c
此方法将对不存在的键使用 默认值
h = {foo: {bar: [:a, :b, :c]}} h.dig(:hello) # => nil h.default_proc = -> (hash, _key) { hash } h.dig(:hello, :world) # => h h.dig(:hello, :world, :foo, :bar, 2) # => :c
static VALUE rb_hash_dig(int argc, VALUE *argv, VALUE self) { rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); self = rb_hash_aref(self, *argv); if (!--argc) return self; ++argv; return rb_obj_dig(argc, argv, self, Qnil); }
使用每个键值对调用给定的块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
输出
foo: 0 bar: 1 baz: 2
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair> h1 = e.each {|key, value| puts "#{key}: #{value}"} h1 # => {:foo=>0, :bar=>1, :baz=>2}
输出
foo: 0 bar: 1 baz: 2
使用每个键调用给定的块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_key {|key| puts key } # => {:foo=>0, :bar=>1, :baz=>2}
输出
foo bar baz
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_key # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_key> h1 = e.each {|key| puts key } h1 # => {:foo=>0, :bar=>1, :baz=>2}
输出
foo bar baz
static VALUE rb_hash_each_key(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_foreach(hash, each_key_i, 0); return hash; }
使用每个键值对调用给定的块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
输出
foo: 0 bar: 1 baz: 2
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair> h1 = e.each {|key, value| puts "#{key}: #{value}"} h1 # => {:foo=>0, :bar=>1, :baz=>2}
输出
foo: 0 bar: 1 baz: 2
static VALUE rb_hash_each_pair(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); if (rb_block_pair_yield_optimizable()) rb_hash_foreach(hash, each_pair_i_fast, 0); else rb_hash_foreach(hash, each_pair_i, 0); return hash; }
使用每个值调用给定的块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_value {|value| puts value } # => {:foo=>0, :bar=>1, :baz=>2}
输出
0 1 2
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_value # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_value> h1 = e.each {|value| puts value } h1 # => {:foo=>0, :bar=>1, :baz=>2}
输出
0 1 2
static VALUE rb_hash_each_value(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_foreach(hash, each_value_i, 0); return hash; }
如果没有哈希条目,则返回 true
,否则返回 false
{}.empty? # => true {foo: 0, bar: 1, baz: 2}.empty? # => false
static VALUE rb_hash_empty_p(VALUE hash) { return RBOOL(RHASH_EMPTY_P(hash)); }
如果满足以下所有条件,则返回 true
-
object
是 Hash 对象。 -
hash
和object
具有相同的键(与顺序无关)。 -
对于每个键
key
,h[key] eql? object[key]
。
否则,返回 false
。
相等
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1, baz: 2} h1.eql? h2 # => true h3 = {baz: 2, bar: 1, foo: 0} h1.eql? h3 # => true
static VALUE rb_hash_eql(VALUE hash1, VALUE hash2) { return hash_equal(hash1, hash2, TRUE); }
返回一个新的哈希,其中不包括给定 keys
的条目
h = { a: 100, b: 200, c: 300 } h.except(:a) #=> {:b=>200, :c=>300}
忽略任何未找到的给定 keys
。
static VALUE rb_hash_except(int argc, VALUE *argv, VALUE hash) { int i; VALUE key, result; result = hash_dup_with_compare_by_id(hash); for (i = 0; i < argc; i++) { key = argv[i]; rb_hash_delete(result, key); } compact_after_delete(result); return result; }
返回给定 key
的值(如果找到)。
h = {foo: 0, bar: 1, baz: 2} h.fetch(:bar) # => 1
如果未找到 key
且未给定块,则返回 default_value
{}.fetch(:nosuch, :default) # => :default
如果未找到 key
且给出了块,则将 key
传递给块并返回块的返回值
{}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch"
如果没有给定 default_value
或块,则引发 KeyError
。
请注意,此方法不使用 default
或 default_proc
的值。
static VALUE rb_hash_fetch_m(int argc, VALUE *argv, VALUE hash) { VALUE key; st_data_t val; long block_given; rb_check_arity(argc, 1, 2); key = argv[0]; block_given = rb_block_given_p(); if (block_given && argc == 2) { rb_warn("block supersedes default value argument"); } if (hash_stlike_lookup(hash, key, &val)) { return (VALUE)val; } else { if (block_given) { return rb_yield(key); } else if (argc == 1) { VALUE desc = rb_protect(rb_inspect, key, 0); if (NIL_P(desc)) { desc = rb_any_to_s(key); } desc = rb_str_ellipsize(desc, 65); rb_key_err_raise(rb_sprintf("key not found: %"PRIsVALUE, desc), hash, key); } else { return argv[1]; } } }
返回一个新的 Array
,其中包含与给定键 *keys* 关联的值
h = {foo: 0, bar: 1, baz: 2} h.fetch_values(:baz, :foo) # => [2, 0]
如果没有给出参数,则返回一个新的空 Array
。
当给定一个块时,使用每个丢失的键调用该块,将该块的返回值视为该键的值
h = {foo: 0, bar: 1, baz: 2} values = h.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s} values # => [1, 0, "bad", "bam"]
如果没有给定块,则在找不到任何给定键时引发异常。
static VALUE rb_hash_fetch_values(int argc, VALUE *argv, VALUE hash) { VALUE result = rb_ary_new2(argc); long i; for (i=0; i<argc; i++) { rb_ary_push(result, rb_hash_fetch(hash, argv[i])); } return result; }
返回一个新的 Array
对象,它是 self
的一维展平。
默认情况下,嵌套的数组不会展平
h = {foo: 0, bar: [:bat, 3], baz: 2} h.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2]
从 Integer
参数 level
中获取递归展平的深度
h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]} h.flatten(1) # => [:foo, 0, :bar, [:bat, [:baz, [:bat]]]] h.flatten(2) # => [:foo, 0, :bar, :bat, [:baz, [:bat]]] h.flatten(3) # => [:foo, 0, :bar, :bat, :baz, [:bat]] h.flatten(4) # => [:foo, 0, :bar, :bat, :baz, :bat]
当 level
为负时,展平所有嵌套的数组
h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]} h.flatten(-1) # => [:foo, 0, :bar, :bat, :baz, :bat] h.flatten(-2) # => [:foo, 0, :bar, :bat, :baz, :bat]
当 level
为零时,返回等效于 to_a
的值
h = {foo: 0, bar: [:bat, 3], baz: 2} h.flatten(0) # => [[:foo, 0], [:bar, [:bat, 3]], [:baz, 2]] h.flatten(0) == h.to_a # => true
static VALUE rb_hash_flatten(int argc, VALUE *argv, VALUE hash) { VALUE ary; rb_check_arity(argc, 0, 1); if (argc) { int level = NUM2INT(argv[0]); if (level == 0) return rb_hash_to_a(hash); ary = rb_ary_new_capa(RHASH_SIZE(hash) * 2); rb_hash_foreach(hash, flatten_i, ary); level--; if (level > 0) { VALUE ary_flatten_level = INT2FIX(level); rb_funcallv(ary, id_flatten_bang, 1, &ary_flatten_level); } else if (level < 0) { /* flatten recursively */ rb_funcallv(ary, id_flatten_bang, 0, 0); } } else { ary = rb_ary_new_capa(RHASH_SIZE(hash) * 2); rb_hash_foreach(hash, flatten_i, ary); } return ary; }
如果 value
是 self
中的值,则返回 true
,否则返回 false
。
static VALUE rb_hash_has_value(VALUE hash, VALUE val) { VALUE data[2]; data[0] = Qfalse; data[1] = val; rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data); return data[0]; }
返回哈希的 Integer
哈希码。
如果两个哈希对象的内容相同(不考虑顺序),则它们具有相同的哈希码
h1 = {foo: 0, bar: 1, baz: 2} h2 = {baz: 2, bar: 1, foo: 0} h2.hash == h1.hash # => true h2.eql? h1 # => true
static VALUE rb_hash_hash(VALUE hash) { st_index_t size = RHASH_SIZE(hash); st_index_t hval = rb_hash_start(size); hval = rb_hash_uint(hval, (st_index_t)rb_hash_hash); if (size) { rb_hash_foreach(hash, hash_i, (VALUE)&hval); } hval = rb_hash_end(hval); return ST2FIX(hval); }
如果 key
是 self
中的键,则返回 true
,否则返回 false
。
VALUE rb_hash_has_key(VALUE hash, VALUE key) { return RBOOL(hash_stlike_lookup(hash, key, NULL)); }
返回一个包含哈希项的新 String
h = {foo: 0, bar: 1, baz: 2} h.inspect # => "{:foo=>0, :bar=>1, :baz=>2}"
static VALUE rb_hash_inspect(VALUE hash) { if (RHASH_EMPTY_P(hash)) return rb_usascii_str_new2("{}"); return rb_exec_recursive(inspect_hash, hash, 0); }
返回一个新的 Hash 对象,其中每个键值对都已反转
h = {foo: 0, bar: 1, baz: 2} h1 = h.invert h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
覆盖任何重复的新键:(参见 条目顺序)
h = {foo: 0, bar: 0, baz: 0} h.invert # => {0=>:baz}
static VALUE rb_hash_invert(VALUE hash) { VALUE h = rb_hash_new_with_size(RHASH_SIZE(hash)); rb_hash_foreach(hash, rb_hash_invert_i, h); return h; }
对每个键值对调用该块;如果该块返回真值,则保留该条目;否则删除该条目;返回 self
。
h = {foo: 0, bar: 1, baz: 2} h.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.keep_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:keep_if> e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
static VALUE rb_hash_keep_if(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { rb_hash_foreach(hash, keep_if_i, hash); } return hash; }
返回具有给定 value
的第一个找到的条目的键(参见 条目顺序)
h = {foo: 0, bar: 2, baz: 2} h.key(0) # => :foo h.key(2) # => :bar
如果没有找到这样的值,则返回 nil
。
static VALUE rb_hash_key(VALUE hash, VALUE value) { VALUE args[2]; args[0] = value; args[1] = Qnil; rb_hash_foreach(hash, key_i, (VALUE)args); return args[1]; }
返回一个包含 self
中所有键的新 Array
h = {foo: 0, bar: 1, baz: 2} h.keys # => [:foo, :bar, :baz]
VALUE rb_hash_keys(VALUE hash) { st_index_t size = RHASH_SIZE(hash); VALUE keys = rb_ary_new_capa(size); if (size == 0) return keys; if (ST_DATA_COMPATIBLE_P(VALUE)) { RARRAY_PTR_USE(keys, ptr, { if (RHASH_AR_TABLE_P(hash)) { size = ar_keys(hash, ptr, size); } else { st_table *table = RHASH_ST_TABLE(hash); size = st_keys(table, ptr, size); } }); rb_gc_writebarrier_remember(keys); rb_ary_set_len(keys, size); } else { rb_hash_foreach(hash, keys_i, keys); } return keys; }
返回通过将每个 other_hashes
合并到 self
的副本中形成的新 Hash。
other_hashes
中的每个参数都必须是 Hash。
带参数且不带块
-
返回通过将
other_hashes
中的每个连续 Hash 合并到self
中形成的新 Hash 对象。 -
每个新键条目都添加到末尾。
-
每个重复键条目的值都会覆盖前一个值。
示例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h.merge(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
带参数和块
-
返回一个新的 Hash 对象,它是
self
和每个给定哈希的合并。 -
给定的哈希从左到右合并。
-
每个新键条目都添加到末尾。
-
对于每个重复的键
-
使用键以及旧值和新值调用该块。
-
该块的返回值成为该条目的新值。
-
示例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h3 = h.merge(h1, h2) { |key, old_value, new_value| old_value + new_value } h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
不带参数
-
返回
self
的副本。 -
如果给出了块,则忽略该块。
示例
h = {foo: 0, bar: 1, baz: 2} h.merge # => {:foo=>0, :bar=>1, :baz=>2} h1 = h.merge { |key, old_value, new_value| raise 'Cannot happen' } h1 # => {:foo=>0, :bar=>1, :baz=>2}
static VALUE rb_hash_merge(int argc, VALUE *argv, VALUE self) { return rb_hash_update(argc, argv, copy_compare_by_id(rb_hash_dup(self), self)); }
将每个 other_hashes
合并到 self
中;返回 self
。
other_hashes
中的每个参数都必须是 Hash。
带参数且不带块
-
返回
self
,在给定的哈希合并到其中之后。 -
给定的哈希从左到右合并。
-
每个新条目都添加到末尾。
-
每个重复键条目的值都会覆盖前一个值。
示例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h.merge!(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
带参数和块
-
返回
self
,在给定的哈希合并之后。 -
给定的哈希从左到右合并。
-
每个新键条目都添加到末尾。
-
对于每个重复的键
-
使用键以及旧值和新值调用该块。
-
该块的返回值成为该条目的新值。
-
示例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h3 = h.merge!(h1, h2) { |key, old_value, new_value| old_value + new_value } h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
不带参数
-
返回
self
,未修改。 -
如果给出了块,则忽略该块。
示例
h = {foo: 0, bar: 1, baz: 2} h.merge # => {:foo=>0, :bar=>1, :baz=>2} h1 = h.merge! { |key, old_value, new_value| raise 'Cannot happen' } h1 # => {:foo=>0, :bar=>1, :baz=>2}
通过重新计算每个键的哈希索引来重建哈希表;返回 self
。
如果在创建条目后键的哈希值已更改,则哈希表将变为无效。请参见 修改活动哈希键。
VALUE rb_hash_rehash(VALUE hash) { VALUE tmp; st_table *tbl; if (hash_iterating_p(hash)) { rb_raise(rb_eRuntimeError, "rehash during iteration"); } rb_hash_modify_check(hash); if (RHASH_AR_TABLE_P(hash)) { tmp = hash_alloc(0); rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); hash_ar_free_and_clear_table(hash); ar_copy(hash, tmp); } else if (RHASH_ST_TABLE_P(hash)) { st_table *old_tab = RHASH_ST_TABLE(hash); tmp = hash_alloc(0); hash_st_table_init(tmp, old_tab->type, old_tab->num_entries); tbl = RHASH_ST_TABLE(tmp); rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); hash_st_free(hash); RHASH_ST_TABLE_SET(hash, tbl); RHASH_ST_CLEAR(tmp); } hash_verify(hash); return hash; }
返回一个新的哈希对象,其条目全部来自 self
,并且该块返回 false
或 nil
h = {foo: 0, bar: 1, baz: 2} h1 = h.reject {|key, value| key.start_with?('b') } h1 # => {:foo=>0}
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.reject # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject> h1 = e.each {|key, value| key.start_with?('b') } h1 # => {:foo=>0}
static VALUE rb_hash_reject(VALUE hash) { VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); result = hash_dup_with_compare_by_id(hash); if (!RHASH_EMPTY_P(hash)) { rb_hash_foreach(result, delete_if_i, result); compact_after_delete(result); } return result; }
返回 self
,其剩余条目是该块返回 false
或 nil
的条目
h = {foo: 0, bar: 1, baz: 2} h.reject! {|key, value| value < 2 } # => {:baz=>2}
如果没有删除任何条目,则返回 nil
。
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.reject! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject!> e.each {|key, value| key.start_with?('b') } # => {:foo=>0}
static VALUE rb_hash_reject_bang(VALUE hash) { st_index_t n; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify(hash); n = RHASH_SIZE(hash); if (!n) return Qnil; rb_hash_foreach(hash, delete_if_i, hash); if (n == RHASH_SIZE(hash)) return Qnil; return hash; }
用 other_hash
的内容替换 self
的全部内容;返回 self
h = {foo: 0, bar: 1, baz: 2} h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4}
返回一个新的哈希对象,其条目是该块返回真值条目的条目
h = {foo: 0, bar: 1, baz: 2} h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.select # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select> e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
static VALUE rb_hash_select(VALUE hash) { VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); result = hash_dup_with_compare_by_id(hash); if (!RHASH_EMPTY_P(hash)) { rb_hash_foreach(result, keep_if_i, result); compact_after_delete(result); } return result; }
返回 self
,其条目是该块返回真值条目的条目
h = {foo: 0, bar: 1, baz: 2} h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1}
如果没有删除任何条目,则返回 nil
。
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.select! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select!> e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
static VALUE rb_hash_select_bang(VALUE hash) { st_index_t n; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); n = RHASH_SIZE(hash); if (!n) return Qnil; rb_hash_foreach(hash, keep_if_i, hash); if (n == RHASH_SIZE(hash)) return Qnil; return hash; }
删除第一个哈希条目(参见 条目顺序);返回一个包含已删除键和值的 2 元素 Array
h = {foo: 0, bar: 1, baz: 2} h.shift # => [:foo, 0] h # => {:bar=>1, :baz=>2}
如果哈希表为空,则返回 nil。
static VALUE rb_hash_shift(VALUE hash) { struct shift_var var; rb_hash_modify_check(hash); if (RHASH_AR_TABLE_P(hash)) { var.key = Qundef; if (!hash_iterating_p(hash)) { if (ar_shift(hash, &var.key, &var.val)) { return rb_assoc_new(var.key, var.val); } } else { rb_hash_foreach(hash, shift_i_safe, (VALUE)&var); if (!UNDEF_P(var.key)) { rb_hash_delete_entry(hash, var.key); return rb_assoc_new(var.key, var.val); } } } if (RHASH_ST_TABLE_P(hash)) { var.key = Qundef; if (!hash_iterating_p(hash)) { if (st_shift(RHASH_ST_TABLE(hash), &var.key, &var.val)) { return rb_assoc_new(var.key, var.val); } } else { rb_hash_foreach(hash, shift_i_safe, (VALUE)&var); if (!UNDEF_P(var.key)) { rb_hash_delete_entry(hash, var.key); return rb_assoc_new(var.key, var.val); } } } return Qnil; }
返回 self
中条目的数量
{foo: 0, bar: 1, baz: 2}.length # => 3
VALUE rb_hash_size(VALUE hash) { return INT2FIX(RHASH_SIZE(hash)); }
返回一个包含给定keys
的条目的新 Hash 对象
h = {foo: 0, bar: 1, baz: 2} h.slice(:baz, :foo) # => {:baz=>2, :foo=>0}
忽略任何未找到的给定 keys
。
static VALUE rb_hash_slice(int argc, VALUE *argv, VALUE hash) { int i; VALUE key, value, result; if (argc == 0 || RHASH_EMPTY_P(hash)) { return copy_compare_by_id(rb_hash_new(), hash); } result = copy_compare_by_id(rb_hash_new_with_size(argc), hash); for (i = 0; i < argc; i++) { key = argv[i]; value = rb_hash_lookup2(hash, key, Qundef); if (!UNDEF_P(value)) rb_hash_aset(result, key, value); } return result; }
将给定的值
与给定的键
关联;返回值
。
如果给定的键
存在,则用给定的值
替换其值;顺序不受影响(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:foo] = 2 # => 2 h.store(:bar, 3) # => 3 h # => {:foo=>2, :bar=>3}
如果键
不存在,则添加键
和值
;新条目按顺序排列在最后(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:baz] = 2 # => 2 h.store(:bat, 3) # => 3 h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
对于 Hash 实例,返回self
。
对于 Hash 子类,返回包含self
内容的新 Hash。
当给定一个块时,返回一个内容基于该块的新 Hash 对象;该块应返回一个指定要包含在返回的 Array 中的键值对的 2 元素Array
对象
h = {foo: 0, bar: 1, baz: 2} h1 = h.to_h {|key, value| [value, key] } h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
static VALUE rb_hash_to_h(VALUE hash) { if (rb_block_given_p()) { return rb_hash_to_h_block(hash); } if (rb_obj_class(hash) != rb_cHash) { const VALUE flags = RBASIC(hash)->flags; hash = hash_dup(hash, rb_cHash, flags & RHASH_PROC_DEFAULT); } return hash; }
返回self
。
static VALUE rb_hash_to_hash(VALUE hash) { return hash; }
返回一个将键映射到其值的Proc
对象
h = {foo: 0, bar: 1, baz: 2} proc = h.to_proc proc.class # => Proc proc.call(:foo) # => 0 proc.call(:bar) # => 1 proc.call(:nosuch) # => nil
static VALUE rb_hash_to_proc(VALUE hash) { return rb_func_lambda_new(hash_proc_call, hash, 1, 1); }
返回一个新的 Hash 对象;每个条目具有
-
由块提供的键。
-
来自
self
的值。
可以提供一个可选的哈希参数来将键映射到新键。任何未给定的键都将使用提供的块进行映射,或者如果没有给出块,则保持不变。
转换键
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_keys {|key| key.to_s } h1 # => {"foo"=>0, "bar"=>1, "baz"=>2} h.transform_keys(foo: :bar, bar: :foo) #=> {bar: 0, foo: 1, baz: 2} h.transform_keys(foo: :hello, &:to_s) #=> {:hello=>0, "bar"=>1, "baz"=>2}
覆盖重复键的值
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_keys {|key| :bat } h1 # => {:bat=>2}
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.transform_keys # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_keys> h1 = e.each { |key| key.to_s } h1 # => {"foo"=>0, "bar"=>1, "baz"=>2}
static VALUE rb_hash_transform_keys(int argc, VALUE *argv, VALUE hash) { VALUE result; struct transform_keys_args transarg = {0}; argc = rb_check_arity(argc, 0, 1); if (argc > 0) { transarg.trans = to_hash(argv[0]); transarg.block_given = rb_block_given_p(); } else { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); } result = rb_hash_new(); if (!RHASH_EMPTY_P(hash)) { if (transarg.trans) { transarg.result = result; rb_hash_foreach(hash, transform_keys_hash_i, (VALUE)&transarg); } else { rb_hash_foreach(hash, transform_keys_i, result); } } return result; }
与 Hash#transform_keys
相同,但原地修改接收器,而不是返回新哈希。
static VALUE rb_hash_transform_keys_bang(int argc, VALUE *argv, VALUE hash) { VALUE trans = 0; int block_given = 0; argc = rb_check_arity(argc, 0, 1); if (argc > 0) { trans = to_hash(argv[0]); block_given = rb_block_given_p(); } else { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); } rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { long i; VALUE new_keys = hash_alloc(0); VALUE pairs = rb_ary_hidden_new(RHASH_SIZE(hash) * 2); rb_hash_foreach(hash, flatten_i, pairs); for (i = 0; i < RARRAY_LEN(pairs); i += 2) { VALUE key = RARRAY_AREF(pairs, i), new_key, val; if (!trans) { new_key = rb_yield(key); } else if (!UNDEF_P(new_key = rb_hash_lookup2(trans, key, Qundef))) { /* use the transformed key */ } else if (block_given) { new_key = rb_yield(key); } else { new_key = key; } val = RARRAY_AREF(pairs, i+1); if (!hash_stlike_lookup(new_keys, key, NULL)) { rb_hash_stlike_delete(hash, &key, NULL); } rb_hash_aset(hash, new_key, val); rb_hash_aset(new_keys, new_key, Qnil); } rb_ary_clear(pairs); rb_hash_clear(new_keys); } compact_after_delete(hash); return hash; }
返回一个新的 Hash 对象;每个条目具有
-
self
中的一个键。 -
由块提供的某个值。
转换值
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_values {|value| value * 100} h1 # => {:foo=>0, :bar=>100, :baz=>200}
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.transform_values # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values> h1 = e.each { |value| value * 100} h1 # => {:foo=>0, :bar=>100, :baz=>200}
static VALUE rb_hash_transform_values(VALUE hash) { VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); result = hash_dup_with_compare_by_id(hash); SET_DEFAULT(result, Qnil); if (!RHASH_EMPTY_P(hash)) { rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result); compact_after_delete(result); } return result; }
返回 self
,其键保持不变,其值由给定的块确定。
h = {foo: 0, bar: 1, baz: 2} h.transform_values! {|value| value * 100} # => {:foo=>0, :bar=>100, :baz=>200}
如果没有给定块,则返回一个新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.transform_values! # => #<Enumerator: {:foo=>0, :bar=>100, :baz=>200}:transform_values!> h1 = e.each {|value| value * 100} h1 # => {:foo=>0, :bar=>100, :baz=>200}
static VALUE rb_hash_transform_values_bang(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash); } return hash; }
返回一个包含 self
中所有值的新 Array
h = {foo: 0, bar: 1, baz: 2} h.values # => [0, 1, 2]
VALUE rb_hash_values(VALUE hash) { VALUE values; st_index_t size = RHASH_SIZE(hash); values = rb_ary_new_capa(size); if (size == 0) return values; if (ST_DATA_COMPATIBLE_P(VALUE)) { if (RHASH_AR_TABLE_P(hash)) { rb_gc_writebarrier_remember(values); RARRAY_PTR_USE(values, ptr, { size = ar_values(hash, ptr, size); }); } else if (RHASH_ST_TABLE_P(hash)) { st_table *table = RHASH_ST_TABLE(hash); rb_gc_writebarrier_remember(values); RARRAY_PTR_USE(values, ptr, { size = st_values(table, ptr, size); }); } rb_ary_set_len(values, size); } else { rb_hash_foreach(hash, values_i, values); } return values; }
返回一个包含给定 keys
的值的新 Array
h = {foo: 0, bar: 1, baz: 2} h.values_at(:baz, :foo) # => [2, 0]
对于任何找不到的键,将返回 默认值
h.values_at(:hello, :foo) # => [nil, 0]
static VALUE rb_hash_values_at(int argc, VALUE *argv, VALUE hash) { VALUE result = rb_ary_new2(argc); long i; for (i=0; i<argc; i++) { rb_ary_push(result, rb_hash_aref(hash, argv[i])); } return result; }