类 Hash
Hash 将每个唯一的键映射到特定的值。
Hash 数据语法¶ ↑
较旧的 Hash 数据语法使用“哈希火箭”,即 =>
h = {:foo => 0, :bar => 1, :baz => 2} h # => {:foo=>0, :bar=>1, :baz=>2}
或者,仅对于 Hash 的键是 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}
但是,尝试对非裸词或字符串的键使用 JSON 风格语法是错误的
# 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}
可以使用 Hash 初始化对象
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 对象:
可以使用以下方式将某些对象转换为哈希:
-
方法
Hash。
创建一个空的 Hash
h = Hash.new h # => {} h.class # => Hash
创建一个空的 Hash
h = Hash[] h # => {}
使用初始条目创建一个 Hash
h = Hash[foo: 0, bar: 1, baz: 2] h # => {:foo=>0, :bar=>1, :baz=>2}
可以通过使用其字面形式(花括号)来创建 Hash。
创建一个空的 Hash
h = {} h # => {}
使用初始条目创建一个 Hash
h = {foo: 0, bar: 1, baz: 2} h # => {:foo=>0, :bar=>1, :baz=>2}
Hash 值基础¶ ↑
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}
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返回的String。
新的 Hash 根据给定的条目具有其初始排序
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 键¶ ↑
Hash 键等价性¶ ↑
当两个对象的 hash 值相同且两个对象彼此 eql? 时,它们被视为相同的哈希键。
修改活动的 Hash 键¶ ↑
在使用 Hash 键时对其进行修改会损坏哈希的索引。
此 Hash 具有作为数组的键
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
并损坏 Hash 索引
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 将被替换为重复且冻结的字符串
s = 'foo' s.frozen? # => false h = {s => 0} first_key = h.keys.first first_key.frozen? # => true
用户定义的 Hash 键¶ ↑
要用作 Hash 键,对象必须实现方法 hash 和 eql?。注意:如果 Hash 使用 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 需要返回与特定键关联的值。当找不到该键时,该值将由其默认 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
当找不到键时,此默认值将返回给 []、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
默认 Proc¶ ↑
当 Hash 的默认 proc 被设置(即不是 nil)时,方法 [] 返回的默认值仅由默认 proc 确定。
可以使用方法 default_proc 检索默认 proc
h = Hash.new h.default_proc # => nil
可以通过调用带有块的 Hash.new 或调用方法 default_proc= 来设置默认 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
当设置了默认 proc(即不是 nil)并且使用不存在的键调用方法 [] 时,[] 将使用 Hash 对象本身和缺失的键调用默认 proc,然后返回 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 将清除默认值,反之亦然。
请注意,修改哈希的默认 proc 不是线程安全的,因为多个线程可以同时为同一个键调用默认 proc。
此处内容¶ ↑
首先,其他地方的内容。类 Hash
-
继承自 类 Object。
-
包含 模块 Enumerable,该模块提供了数十种其他方法。
此处,类 Hash 提供了对以下操作有用的方法:
类 Hash 还包括来自模块 Enumerable 的方法。
用于创建 Hash 的方法¶ ↑
-
::[]:返回使用给定对象填充的新哈希。 -
::new: 返回一个新的空哈希。 -
::try_convert: 返回一个由给定对象创建的新哈希。
用于设置 Hash 状态的方法¶ ↑
-
compare_by_identity: 设置self在比较键时仅考虑标识。 -
default=: 将默认值设置为给定值。 -
default_proc=: 将默认 proc 设置为给定的 proc。 -
rehash: 通过重新计算每个键的哈希索引来重建哈希表。
用于查询的方法¶ ↑
-
any?: 返回是否任何元素满足给定的标准。 -
compare_by_identity?: 返回哈希在比较键时是否仅考虑标识。 -
default: 返回默认值,或给定键的默认值。 -
default_proc: 返回默认 proc。 -
empty?: 返回是否没有条目。 -
eql?: 返回给定对象是否等于self。 -
hash: 返回整数哈希码。 -
has_value?(别名为value?): 返回给定对象是否为self中的值。
用于比较的方法¶ ↑
-
<: 返回self是否为给定对象的真子集。 -
<=: 返回self是否为给定对象的子集。 -
==: 返回给定对象是否等于self。 -
>: 返回self是否为给定对象的真超集。 -
>=: 返回self是否为给定对象的超集。
用于获取的方法¶ ↑
-
[]: 返回与给定键关联的值。 -
assoc: 返回一个包含给定键及其值的 2 元素数组。 -
dig: 返回嵌套对象中由给定键和其他参数指定的对象。 -
fetch: 返回给定键的值。 -
fetch_values: 返回包含与给定键关联的值的数组。 -
key: 返回第一个找到的具有给定值的条目的键。 -
keys: 返回一个包含self中所有键的数组。 -
rassoc: 返回一个包含第一个找到的具有给定值的条目的键和值的 2 元素数组。 -
values: 返回一个包含self中所有值的数组。 -
values_at: 返回一个包含给定键的值的数组。
用于赋值的方法¶ ↑
-
merge: 返回通过将每个给定哈希合并到self的副本中而形成的哈希。 -
replace(别名为initialize_copy): 将self的全部内容替换为给定哈希的内容。
用于删除的方法¶ ↑
这些方法从 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: 如果是Hash,则返回self;如果是Hash的子类,则返回一个包含来自self的条目的Hash。 -
to_hash: 返回self。 -
to_proc: 返回一个将给定键映射到其值的 proc。
用于转换键和值的方法¶ ↑
-
transform_keys: 返回self的副本,并修改了键。 -
transform_keys!: 修改self中的键。 -
transform_values: 返回self的副本,并修改了值。 -
transform_values!: 修改self中的值。
其他方法¶ ↑
公共类方法
来源
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 对象,其中填充了给定的对象(如果有)。请参阅 Hash::new。
如果没有参数,则返回一个新的空 Hash。
当给定的单个参数是 Hash 时,返回一个新的 Hash,其中填充了给定 Hash 中的条目,不包括默认值或 proc。
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}
如果参数列表不符合上述任何条件,则引发异常。
来源
# File hash.rb, line 37 def initialize(ifnone = (ifnone_unset = true), capacity: 0, &block) Primitive.rb_hash_init(capacity, ifnone_unset, ifnone, block) end
返回一个新的空 Hash 对象。
新哈希的初始默认值和初始默认 proc 取决于上面使用的形式。请参阅 默认值。
如果既没有给出参数也没有给出块,则将默认值和默认 proc 都初始化为 nil。
h = Hash.new h.default # => nil h.default_proc # => nil
如果给出了参数 default_value 但没有给出块,则将默认值初始化为给定的 default_value,并将默认 proc 初始化为 nil。
h = Hash.new(false) h.default # => false h.default_proc # => nil
如果给出了块但没有给出 default_value,则将该块存储为默认 proc,并将默认值设置为 nil。
h = Hash.new {|hash, key| "Default value for #{key}" } h.default # => nil h.default_proc.class # => Proc h[:nosuch] # => "Default value for nosuch"
如果同时给出了块和 default_value,则引发 ArgumentError。
如果给出了可选的关键字参数 capacity,则将分配哈希,使其具有足够的容量来容纳这么多键,而无需调整大小。
来源
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;
}
复制给定的哈希并添加 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_p(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
return RBOOL(RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS);
}
检查给定的哈希是否由 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_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 # => false
来源
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);
}
如果 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_equal(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, FALSE);
}
如果以下所有条件都为真,则返回 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_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 # => false
来源
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);
}
如果 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
来源
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);
}
}
如果找到,则返回与给定 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_aset(VALUE hash, VALUE key, VALUE val)
{
bool iter_p = hash_iterating_p(hash);
rb_hash_modify(hash);
if (!RHASH_STRING_KEY_P(hash, key)) {
RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val);
}
else {
RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val);
}
return val;
}
将给定的 value 与给定的 key 关联;返回 value。
如果给定的 key 存在,则将其值替换为给定的 value;顺序不受影响(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:foo] = 2 # => 2 h.store(:bar, 3) # => 3 h # => {:foo=>2, :bar=>3}
如果 key 不存在,则添加 key 和 value;新条目在顺序中位于最后(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:baz] = 2 # => 2 h.store(:bat, 3) # => 3 h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
来源
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];
}
如果任何元素满足给定的条件,则返回 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_assoc(VALUE hash, VALUE key)
{
VALUE args[2];
if (RHASH_EMPTY_P(hash)) return Qnil;
if (RHASH_ST_TABLE_P(hash) && !RHASH_IDENTHASH_P(hash)) {
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];
}
如果找到给定的 key,则返回一个包含该键及其值的 2 元素 Array
h = {foo: 0, bar: 1, baz: 2} h.assoc(:bar) # => [:bar, 1]
如果未找到键 key,则返回 nil。
来源
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。
来源
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;
}
返回一个删除所有 nil 值条目的 self 的副本
h = {foo: 0, bar: nil, baz: 2, bat: nil} h1 = h.compact h1 # => {:foo=>0, :baz=>2}
来源
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,其中所有 nil 值条目都已删除(就地删除)
h = {foo: 0, bar: nil, baz: 2, bat: nil} h.compact! # => {:foo=>0, :baz=>2}
如果没有删除任何条目,则返回 nil。
来源
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;
}
设置 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_p(VALUE hash)
{
return RBOOL(RHASH_IDENTHASH_P(hash));
}
如果调用了 compare_by_identity,则返回 true,否则返回 false。
来源
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;
}
返回给定 key 的默认值。返回的值将由默认的 proc 或默认值确定。请参阅默认值。
如果没有参数,则返回当前的默认值
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_set_default(VALUE hash, VALUE ifnone)
{
rb_hash_modify_check(hash);
SET_DEFAULT(hash, ifnone);
return ifnone;
}
将默认值设置为 value;返回 value
h = {} h.default # => nil h.default = false # => false h.default # => false
请参阅默认值。
来源
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
来源
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;
}
将 self 的默认 proc 设置为 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
来源
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;
}
}
}
删除给定 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}
来源
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;
}
如果给定了块,则使用每个键值对调用该块;删除该块返回真值的每个条目;返回 self
h = {foo: 0, bar: 1, baz: 2} h.delete_if {|key, value| value > 0 } # => {:foo=>0}
如果没有给定块,则返回一个新的 Enumerator
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}
来源
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);
}
查找并返回嵌套对象中由 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
使用每个键值对调用给定的块;返回 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_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_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_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_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_value(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_foreach(hash, each_value_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
来源
VALUE
rb_hash_empty_p(VALUE hash)
{
return RBOOL(RHASH_EMPTY_P(hash));
}
如果没有任何哈希条目,则返回 true,否则返回 false
{}.empty? # => true
{foo: 0, bar: 1, baz: 2}.empty? # => false
来源
static VALUE
rb_hash_eql(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, TRUE);
}
如果以下所有条件都为真,则返回 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_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;
}
返回一个新的 Hash,其中排除给定 keys 的条目
h = { a: 100, b: 200, c: 300 } h.except(:a) #=> {:b=>200, :c=>300}
任何找不到的给定 keys 都会被忽略。
来源
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];
}
}
}
如果找到,则返回给定 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_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,其中包含与给定键 *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_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;
}
返回一个新的 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_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];
}
如果 value 是 self 中的值,则返回 true,否则返回 false。
来源
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);
}
返回哈希的 Integer 哈希码。
如果两个 Hash 对象的内容相同(无论顺序如何),则它们具有相同的哈希码
h1 = {foo: 0, bar: 1, baz: 2} h2 = {baz: 2, bar: 1, foo: 0} h2.hash == h1.hash # => true h2.eql? h1 # => true
来源
VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
return RBOOL(hash_stlike_lookup(hash, key, NULL));
}
如果 key 是 self 中的键,则返回 true,否则返回 false。
来源
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);
}
返回一个包含哈希条目的新 String
h = {foo: 0, bar: 1, baz: 2} h.inspect # => "{foo: 0, bar: 1, baz: 2}"
来源
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;
}
返回一个键值对反转的新 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_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;
}
对每个键值对调用块;如果该块返回真值,则保留该条目;否则删除该条目;返回 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_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];
}
返回具有给定 value 的第一个找到的条目的键(请参阅条目顺序)
h = {foo: 0, bar: 2, baz: 2} h.key(0) # => :foo h.key(2) # => :bar
如果没有找到这样的值,则返回 nil。
来源
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;
}
返回一个包含 self 中所有键的新 Array
h = {foo: 0, bar: 1, baz: 2} h.keys # => [:foo, :bar, :baz]
来源
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 的副本中而形成的新 Hash。
other_hashes 中的每个参数都必须是 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}
将每个 other_hashes 合并到 self 中;返回 self。
other_hashes 中的每个参数都必须是 Hash。
带有参数且没有块
-
在给定哈希值合并到
self之后,返回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}
来源
来源
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。
如果条目创建后键的哈希值发生了更改,则哈希表将变为无效。请参阅修改活动哈希键。
来源
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;
}
返回一个新的 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_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;
}
返回 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}
使用 other_hash 的内容替换 self 的全部内容;返回 self
h = {foo: 0, bar: 1, baz: 2} h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4}
来源
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;
}
返回一个新的 Hash 对象,其条目是代码块返回真值的条目
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_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;
}
返回 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_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;
}
删除第一个哈希条目(请参阅条目顺序);返回一个双元素 Array,其中包含删除的键和值
h = {foo: 0, bar: 1, baz: 2} h.shift # => [:foo, 0] h # => {:bar=>1, :baz=>2}
如果哈希为空,则返回 nil。
来源
VALUE
rb_hash_size(VALUE hash)
{
return INT2FIX(RHASH_SIZE(hash));
}
返回 self 中条目的计数
{foo: 0, bar: 1, baz: 2}.length # => 3
来源
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;
}
返回一个新的 Hash 对象,其中包含给定 keys 的条目
h = {foo: 0, bar: 1, baz: 2} h.slice(:baz, :foo) # => {:baz=>2, :foo=>0}
任何找不到的给定 keys 都会被忽略。
将给定的 value 与给定的 key 关联;返回 value。
如果给定的 key 存在,则将其值替换为给定的 value;顺序不受影响(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:foo] = 2 # => 2 h.store(:bar, 3) # => 3 h # => {:foo=>2, :bar=>3}
如果 key 不存在,则添加 key 和 value;新条目在顺序中位于最后(请参阅条目顺序)
h = {foo: 0, bar: 1} h[:baz] = 2 # => 2 h.store(:bat, 3) # => 3 h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
来源
来源
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;
}
对于 Hash 的实例,返回 self。
对于 Hash 的子类,返回一个新的 Hash,其中包含 self 的内容。
当给出代码块时,返回一个新的 Hash 对象,其内容基于该代码块;代码块应返回一个双元素 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_proc(VALUE hash)
{
return rb_func_lambda_new(hash_proc_call, hash, 1, 1);
}
返回一个将键映射到其值的 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_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 对象;每个条目都有
-
由代码块提供的键。
-
来自
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_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#transform_keys 相同,但就地修改接收器,而不是返回新的哈希值。
来源
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;
}
返回一个新的 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_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,其键保持不变,其值由给定的代码块确定。
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}
来源
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;
}
返回一个新的 Array,其中包含 self 中的所有值
h = {foo: 0, bar: 1, baz: 2} h.values # => [0, 1, 2]
来源
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;
}
返回一个新的 Array,其中包含给定 keys 的值
h = {foo: 0, bar: 1, baz: 2} h.values_at(:baz, :foo) # => [2, 0]
对于任何未找到的键,将返回默认值
h.values_at(:hello, :foo) # => [nil, 0]