类 Hash

Hash 将其每个唯一的键映射到一个特定的值。

Hash 与 Array 有一些相似之处,但

  • 数组索引始终是Integer

  • 哈希键可以是(几乎)任何对象。

哈希数据语法

哈希数据的旧语法使用“哈希火箭”=>

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}

但对于不是裸词或字符串的键,尝试使用 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.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}

条目顺序

哈希对象按其创建顺序呈现其条目。这在以下方面可见:

  • 迭代方法,如 eacheach_keyeach_paireach_value

  • 其他对顺序敏感的方法,如 shiftkeysvalues

  • 方法 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将被替换为重复的冻结字符串

s = 'foo'
s.frozen? # => false
h = {s => 0}
first_key = h.keys.first
first_key.frozen? # => true

用户定义的哈希键

要作为哈希键使用,对象必须实现方法hasheql?。注意:如果哈希使用compare_by_identity,则此要求不适用,因为比较将依赖于键的object id而不是hasheql?

Objecthasheq?定义了基本实现,这使得每个对象成为一个独特的键。通常,用户定义的类将希望覆盖这些方法以提供有意义的行为,或者例如继承Struct,它对这些方法有有用的定义。

hash的典型实现基于对象的 data,而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_atdig需要返回与特定键关联的值。当找不到该键时,该值将由其默认 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_atdig

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

当哈希的默认 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,并且方法 [] 被调用时,传入一个不存在的键,[] 会调用默认 proc,并将哈希对象本身和缺失的键作为参数传递给 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

这里,类 Hash 提供了对以下方面有用的函数:

类 Hash 还包含模块 Enumerable 中的函数。

创建哈希的函数

  • ::[]: 返回一个使用给定对象填充的新哈希。

  • ::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 中的值。

  • include?, has_key?, member?, key?: 返回给定对象是否是 self 中的键。

  • length, size: 返回条目的数量。

  • value?: 返回给定对象是否是 self 中的值。

比较方法

  • #<: 返回 self 是否是给定对象的真子集。

  • #<=: 返回 self 是否是给定对象的子集。

  • ==: 返回给定对象是否等于 self

  • #>: 返回 self 是否是给定对象的真超集

  • #>=: 返回 self 是否是给定对象的超集。

获取方法

  • []: 返回与给定键关联的值。

  • assoc: 返回包含给定键及其值的 2 元素数组。

  • dig: 返回嵌套对象中由给定键和附加参数指定的对象。

  • fetch: 返回给定键的值。

  • fetch_values: 返回包含与给定键关联的值的数组。

  • key: 返回第一个找到的具有给定值的条目的键。

  • keys: 返回包含 self 中所有键的数组。

  • rassoc: 返回一个包含第一个找到的具有给定值的条目的键和值的 2 元素数组。

  • values: 返回包含 self 中所有值的数组。

  • values_at: 返回包含给定键的值的数组。

分配方法

  • []=, store: 将给定键与给定值关联。

  • merge: 返回通过将每个给定哈希合并到 self 的副本中形成的哈希。

  • merge!, update: 将每个给定哈希合并到 self 中。

  • replace: 用给定哈希的内容替换 self 的全部内容。

删除方法

这些方法从 self 中删除条目

  • clear: 从 self 中删除所有条目。

  • compact!: 从 self 中删除所有 nil 值的条目。

  • delete: 删除给定键的条目。

  • delete_if: 删除由给定块选择的条目。

  • filter!, select!: 只保留由给定块选择的条目。

  • keep_if: 只保留由给定块选择的条目。

  • reject!: 删除由给定块选择的条目。

  • shift: 删除并返回第一个条目。

这些方法返回 self 的副本,其中删除了一些条目

  • compact: 返回 self 的副本,其中删除了所有 nil 值的条目。

  • except: 返回 self 的副本,其中删除了指定键的条目。

  • filter, select: 返回 self 的副本,其中只包含由给定块选择的条目。

  • reject: 返回 self 的副本,其中删除了由给定块指定的条目。

  • slice: 返回包含给定键的条目的哈希。

迭代方法

  • each, each_pair: 对每个键值对调用给定的代码块。

  • each_key: 对每个键调用给定的代码块。

  • each_value: 对每个值调用给定的代码块。

转换方法

  • inspect, to_s: 返回一个新的 String,其中包含哈希条目。

  • to_a: 返回一个新的二维数组;每个嵌套数组包含来自 self 的一个键值对。

  • to_h: 如果是 Hash,则返回 self;如果是 Hash 的子类,则返回一个包含来自 self 的条目的 Hash。

  • to_hash: 返回 self

  • to_proc: 返回一个 proc,它将给定的键映射到其值。

转换键和值的方法

其他方法

  • flatten: 返回一个数组,它是 self 的一维扁平化。

  • invert: 返回一个哈希,其中每个键值对都被反转。

公共类方法

Hash[] → new_empty_hash click to toggle source
Hash[hash] → new_hash
Hash[ [*2_element_arrays] ] → new_hash
Hash[*objects] → new_hash

返回一个新的 Hash 对象,其中填充了给定的对象(如果有)。参见 Hash::new.

如果没有参数,则返回一个新的空 Hash。

当给定的单个参数是 Hash 时,返回一个新的 Hash,其中填充了来自给定 Hash 的条目,不包括默认值或 proc。

h = {foo: 0, bar: 1, baz: 2}
Hash[h] # => {:foo=>0, :bar=>1, :baz=>2}

当给定的单个参数是 Array 的二维数组时,返回一个新的 Hash 对象,其中每个二维数组形成一个键值条目。

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;
}
new(default_value = nil) → new_hash 点击切换源代码
new {|hash, key| ... } → new_hash

返回一个新的空 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

如果给出了代码块但没有给出参数,则将代码块存储为默认 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"
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_hash(hash) → 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;
}
ruby2_keywords_hash?(hash) → true 或 false 点击切换源代码

检查给定的哈希是否被 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);
}
try_convert(obj) → obj、new_hash 或 nil 点击切换源代码

如果 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 点击切换源代码

如果 hashother_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 点击切换源代码

如果 hashother_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);
}
hash == object → true 或 false 点击切换源代码

如果以下所有条件都为真,则返回 true

  • object 是一个 Hash 对象。

  • hashobject 具有相同的键(无论顺序如何)。

  • 对于每个键 keyhash[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 点击切换源代码

如果 hashother_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 点击切换源代码

如果 hashother_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);
}
hash[key] → value 点击切换源代码

如果找到,则返回与给定 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);
    }
}
hash[key] = value → value 点击切换源代码

将给定的 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 不存在,则添加 keyvalue;新条目在顺序中最后(参见 条目顺序)。

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;
}
也被称为:store
any? → true 或 false 点击切换源代码
any?(object) → true 或 false
any? {|key, value| ... } → true 或 false

如果任何元素满足给定条件,则返回 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

相关:Enumerable#any?

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];
}
assoc(key) → new_array 或 nil 点击切换源代码

如果找到给定的 key,则返回一个包含该键及其值的 2 元素 Array

h = {foo: 0, bar: 1, baz: 2}
h.assoc(:bar) # => [:bar, 1]

如果未找到键 key,则返回 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];
}
clear → self 点击切换源代码

删除所有哈希条目;返回 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;
}
compact → new_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;
}
compact! → self 或 nil 点击切换源代码

返回 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;
}
compare_by_identity → self 点击切换源代码

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 点击切换源代码

如果已调用 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);
}
default → object 点击切换源代码
default(key) → object

返回给定 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_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;
}
default = value → object 点击切换源代码

将默认值设置为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;
}
default_proc → proc 或 nil 点击切换源代码

返回self的默认 proc(参见 默认值

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;
}
default_proc = proc → 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
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;
}
delete(key) → value 或 nil 点击切换源代码
delete(key) {|key| ... } → object

删除给定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;
        }
    }
}
delete_if {|key, value| ... } → self 点击切换源代码
delete_if → new_enumerator

如果给出块,则使用每个键值对调用块;删除块返回真值的每个条目;返回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}
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;
}
dig(key, *identifiers) → object 点击切换源代码

查找并返回由keyidentifiers指定的嵌套对象中的对象。嵌套对象可以是各种类的实例。参见 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);
}
each {|key, value| ... } → self
each → new_enumerator

使用每个键值对调用给定的块;返回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
别名:each_pair
each_key {|key| ... } → self 点击切换源代码
each_key → new_enumerator

使用每个键调用给定的块;返回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;
}
each_pair -> new_enumerator 点击切换源代码

使用每个键值对调用给定的块;返回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;
}
别名:each
each_value {|value| ... } → self 点击切换源代码
each_value → new_enumerator

对每个值调用给定的代码块;返回 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;
}
empty? → true or false 点击切换源代码

如果没有任何哈希条目,则返回 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));
}
eql? object → true or false 点击切换源代码

如果以下所有条件都为真,则返回 true

  • object 是一个 Hash 对象。

  • hashobject 具有相同的键(无论顺序如何)。

  • 对于每个键 keyh[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);
}
except(*keys) → a_hash 点击切换源代码

返回一个新的 Hash,不包括给定 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;
}
fetch(key) → object 点击切换源代码
fetch(key, default_value) → object
fetch(key) {|key| ... } → object

返回给定 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

请注意,此方法不使用 defaultdefault_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];
        }
    }
}
fetch_values(*keys) → new_array 点击切换源代码
fetch_values(*keys) {|key| ... } → new_array

返回一个新的 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;
}
filter()

返回一个新的 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}
别名:select
filter!()

返回 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}
别名:select!
flatten → new_array 点击以切换源代码
flatten(level) → new_array

返回一个新的 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;
}
has_key?(key) → true 或 false

如果 keyself 中的键,则返回 true,否则返回 false

别名:include?
has_value?(value) → true 或 false 点击以切换源代码

如果 valueself 中的值,则返回 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];
}
也称为:value?
hash → an_integer 点击以切换源代码

返回哈希的 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
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);
}
include?(key) → true 或 false 点击以切换源代码

如果 keyself 中的键,则返回 true,否则返回 false

VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
    return RBOOL(hash_stlike_lookup(hash, key, NULL));
}
也称为:member?has_key?key?
initialize_copy(other_hash) -> self 点击以切换源代码

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_replace(VALUE hash, VALUE hash2)
{
    rb_hash_modify_check(hash);
    if (hash == hash2) return hash;
    if (hash_iterating_p(hash)) {
        rb_raise(rb_eRuntimeError, "can't replace hash during iteration");
    }
    hash2 = to_hash(hash2);

    COPY_DEFAULT(hash, hash2);

    if (RHASH_AR_TABLE_P(hash)) {
        hash_ar_free_and_clear_table(hash);
    }
    else {
        hash_st_free_and_clear_table(hash);
    }

    hash_copy(hash, hash2);

    return hash;
}
也称为:replace
inspect → new_string 点击切换源代码

返回一个新的 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);
}
别名:to_s
invert → new_hash 点击切换源代码

返回一个新的 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;
}
keep_if {|key, value| ... } → self 点击切换源代码
keep_if → new_enumerator

对每个键值对调用块;如果块返回真值,则保留条目;否则删除条目;返回 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;
}
key(value) → key or nil 点击切换源代码

返回第一个找到的具有给定 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];
}
key?(key) → true or false

如果 keyself 中的键,则返回 true,否则返回 false

别名:include?
keys → new_array 点击切换源代码

返回一个新的 Array 对象,包含 self 中的所有键。

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;
}
length → integer

返回 self 中的条目数量。

{foo: 0, bar: 1, baz: 2}.length # => 3
别名:size
member?(key) → true or false

如果 keyself 中的键,则返回 true,否则返回 false

别名:include?
merge → copy_of_self 点击切换源代码
merge(*other_hashes) → new_hash
merge(*other_hashes) { |key, old_value, new_value| ... } → new_hash

返回一个新的 Hash 对象,该对象是将 other_hashes 中的每个哈希表合并到 self 的副本中形成的。

other_hashes 中的每个参数都必须是 Hash 对象。


带参数,不带块

  • 返回一个新的 Hash 对象,该对象是将 other_hashes 中的每个后续哈希表合并到 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}

带参数,带块

  • 返回一个新的 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));
}
merge! → self
merge!(*other_hashes) → self
merge!(*other_hashes) { |key, old_value, new_value| ... } → self

将每个 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}
别名:update
rassoc(value) → new_array or nil click to toggle source

返回一个新的包含两个元素的 Array,该数组包含第一个找到的条目的键和值,其值为 == 到 value(参见 条目顺序)。

h = {foo: 0, bar: 1, baz: 1}
h.rassoc(1) # => [:bar, 1]

如果未找到此类值,则返回 nil

static VALUE
rb_hash_rassoc(VALUE hash, VALUE obj)
{
    VALUE args[2];

    args[0] = obj;
    args[1] = Qnil;
    rb_hash_foreach(hash, rassoc_i, (VALUE)args);
    return args[1];
}
rehash → self click to toggle source

通过重新计算每个键的哈希索引来重建哈希表;返回 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;
}
reject {|key, value| ... } → new_hash click to toggle source
reject → new_enumerator

返回一个新的 Hash 对象,其条目是 self 中所有块返回 falsenil 的条目。

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;
}
reject! {|key, value| ... } → self or nil click to toggle source
reject! → new_enumerator

返回 self,其剩余条目是块返回 falsenil 的条目。

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;
}
replace(other_hash) → self

other_hash 的内容替换 self 的全部内容;返回 self

h = {foo: 0, bar: 1, baz: 2}
h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4}
别名:initialize_copy
select {|key, value| ... } → new_hash click to toggle source
select → new_enumerator

返回一个新的 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(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;
}
也称为:filter
select! {|key, value| ... } → self 或 nil 点击切换源代码
select! → 新枚举器

返回 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;
}
别名:filter!
shift → [key, value] 或 nil 点击切换源代码

移除第一个哈希条目(参见 条目顺序);返回一个包含移除的键和值的 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;
}
size → 整数 点击切换源代码

返回 self 中的条目数量。

{foo: 0, bar: 1, baz: 2}.length # => 3
VALUE
rb_hash_size(VALUE hash)
{
    return INT2FIX(RHASH_SIZE(hash));
}
别名:length
slice(*keys) → 新哈希 点击切换源代码

返回一个新的 Hash 对象,包含给定 keys 的条目

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;
}
store(key, value)

将给定的 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 不存在,则添加 keyvalue;新条目在顺序中最后(参见 条目顺序)。

h = {foo: 0, bar: 1}
h[:baz] = 2 # => 2
h.store(:bat, 3) # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
别名:[]=
to_a → 新数组 点击切换源代码

返回一个新的 Array 对象,包含 2 元素 Array 对象;每个嵌套的 Array 包含来自 self 的键值对

h = {foo: 0, bar: 1, baz: 2}
h.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
static VALUE
rb_hash_to_a(VALUE hash)
{
    VALUE ary;

    ary = rb_ary_new_capa(RHASH_SIZE(hash));
    rb_hash_foreach(hash, to_a_i, ary);

    return ary;
}
to_h → self 或 新哈希 点击切换源代码
to_h {|key, value| ... } → 新哈希

对于 Hash 实例,返回 self

对于 Hash 的子类,返回一个包含 self 内容的新 Hash。

当给出代码块时,返回一个新的 Hash 对象,其内容基于代码块;代码块应返回一个 2 元素 Array 对象,指定要包含在返回的 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;
}
to_hash → self 点击切换源代码

返回 self

static VALUE
rb_hash_to_hash(VALUE hash)
{
    return hash;
}
to_proc → proc 点击切换源代码

返回一个 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);
}
to_s()

返回一个新的 String 对象,包含哈希表中的所有条目。

h = {foo: 0, bar: 1, baz: 2}
h.inspect # => "{:foo=>0, :bar=>1, :baz=>2}"
别名:inspect
transform_keys {|key| ... } → 新哈希 点击切换源代码
transform_keys(hash2) → 新哈希
transform_keys(hash2) {|other_key| ...} → new_hash
transform_keys → new_enumerator

返回一个新的 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;
}
transform_keys! {|key| ... } → self 点击切换源代码
transform_keys!(hash2) → self
transform_keys!(hash2) {|other_key| ...} → self
transform_keys! → new_enumerator

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;
}
transform_values {|value| ... } → new_hash 点击切换源代码
transform_values → new_enumerator

返回一个新的 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;
}
transform_values! {|value| ... } → self 点击切换源代码
transform_values! → new_enumerator

返回 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;
}
update(*other_hashes) { |key, old_value, new_value| } -> self 点击切换源代码

将每个 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}
static VALUE
rb_hash_update(int argc, VALUE *argv, VALUE self)
{
    int i;
    bool block_given = rb_block_given_p();

    rb_hash_modify(self);
    for (i = 0; i < argc; i++){
        VALUE hash = to_hash(argv[i]);
        if (block_given) {
            rb_hash_foreach(hash, rb_hash_update_block_i, self);
        }
        else {
            rb_hash_foreach(hash, rb_hash_update_i, self);
        }
    }
    return self;
}
也称为:merge!
value?(value) → true 或 false

如果 valueself 中的值,则返回 true,否则返回 false

别名:has_value?
values → new_array 点击切换源代码

返回一个新的 Array,其中包含 self 中的所有值

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;
}
values_at(*keys) → new_array 点击切换源代码

返回一个新的 Array,其中包含给定 keys 的值

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;
}