类哈希

哈希将它的每个唯一键映射到特定值。

哈希与 数组 有某些相似之处,但

哈希数据语法

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

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

或者,仅对哈希键是 Symbol 的情况,可以使用较新的 JSON 风格语法,其中每个裸字都将成为一个 Symbol

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

您还可以使用 String 代替裸字

h = {'foo': 0, 'bar': 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}

您还可以混合使用这些风格

h = {foo: 0, :bar => 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}

但尝试对不是裸字或 String 的键使用 JSON 风格语法会出错

# Raises SyntaxError (syntax error, unexpected ':', expecting =>):
h = {0: 'zero'}

Hash 值可以省略,这意味着该值将通过键的名称从上下文中获取

x = 0
y = 100
h = {x:, y:}
h # => {:x=>0, :y=>100}

常见用法

您可以使用哈希为对象指定名称

person = {name: 'Matz', language: 'Ruby'}
person # => {:name=>"Matz", :language=>"Ruby"}

您可以使用哈希为方法参数指定名称

def some_method(hash)
  p hash
end
some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2}

注意:当方法调用中的最后一个参数是哈希时,可以省略大括号

some_method(foo: 0, bar: 1, baz: 2) # => {:foo=>0, :bar=>1, :baz=>2}

您可以使用哈希初始化对象

class Dev
  attr_accessor :name, :language
  def initialize(hash)
    self.name = hash[:name]
    self.language = hash[:language]
  end
end
matz = Dev.new(name: 'Matz', language: 'Ruby')
matz # => #<Dev: @name="Matz", @language="Ruby">

创建哈希

您可以使用以下方法显式创建哈希对象

您可以使用以下方法将某些对象转换为哈希

您可以通过调用方法 Hash.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}

项顺序

哈希对象按创建顺序显示其项。这在以下内容中可见

新哈希的初始排序顺序由给定的条目决定

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

新条目添加到末尾

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

更新值不会影响顺序

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

但重新创建已删除的条目可能会影响顺序

h.delete(:foo)
h[:foo] = 5
h # => {:bar=>1, :baz=>3, :foo=>5}

哈希键

哈希键等价性

当对象的 hash 值相同且两个对象彼此 eql? 时,它们会被视为相同的哈希键。

修改活动哈希键

在使用过程中修改哈希键会损坏哈希的索引。

此哈希的键是数组

a0 = [ :foo, :bar ]
a1 = [ :baz, :bat ]
h = {a0 => 0, a1 => 1}
h.include?(a0) # => true
h[a0] # => 0
a0.hash # => 110002110

修改数组元素 a0[0] 会更改其哈希值

a0[0] = :bam
a0.hash # => 1069447059

并损坏哈希索引

h.include?(a0) # => false
h[a0] # => nil

可以使用方法 rehash 修复哈希索引

h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1}
h.include?(a0) # => true
h[a0] # => 0

一个 String 键始终是安全的。这是因为作为键传递的未冻结 String 将被复制并冻结的 String 替换

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

用户定义的哈希键

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

Objecthasheq? 定义了基本实现,使每个对象成为一个不同的键。通常,用户定义的类会希望重写这些方法以提供有意义的行为,或者继承具有这些方法的有用定义的 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_atdig 需要返回与特定键关联的值。当找不到该键时,该值将由其默认过程(如果有)或其默认值(最初为“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

当设置 Hash 的默认过程(即不为 nil)时,方法 [] 返回的默认值仅由默认过程决定。

您可以使用 default_proc 方法检索默认过程

h = Hash.new
h.default_proc # => nil

您可以通过使用带块的 Hash.new 或调用 default_proc= 方法来设置默认过程

h = Hash.new { |hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
h.default_proc = proc { |hash, key| "Default value for #{key.inspect}" }
h.default_proc.class # => Proc

当设置默认过程(即不为 nil)并且使用不存在的键调用 [] 方法时,[] 会使用 Hash 对象本身和丢失的键调用默认过程,然后返回过程的返回值

h = Hash.new { |hash, key| "Default value for #{key}" }
h[:nosuch] # => "Default value for nosuch"

请注意,在上面的示例中,不会创建键 :nosuch 的条目

h.include?(:nosuch) # => false

但是,过程本身可以添加新条目

synonyms = Hash.new { |hash, key| hash[key] = [] }
synonyms.include?(:hello) # => false
synonyms[:hello] << :hi # => [:hi]
synonyms[:world] << :universe # => [:universe]
synonyms.keys # => [:hello, :world]

请注意,设置默认过程会清除默认值,反之亦然。

请注意,修改哈希的默认过程在多线程调用同一个键的默认过程时不是线程安全的。

此处内容

首先,其他地方的内容。类 Hash

此处,类 Hash 提供了对以下内容有用的方法

类 Hash 还包括来自模块 Enumerable 的方法。

创建 Hash 的方法

设置哈希状态的方法

查询方法

比较方法

获取方法

分配方法

删除方法

这些方法从 self 中移除条目

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

迭代方法

转换方法

转换键和值的方法

其他方法

公共类方法

Hash[] → new_empty_hash 单击以切换源
Hash[hash] → new_hash
Hash[ [*2_element_arrays] ] → new_hash
Hash[*objects] → new_hash

如果提供任何对象,则返回一个填充了给定对象的新 Hash 对象。请参阅 Hash::new

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

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

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

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

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

当参数计数为偶数时;返回一个新的 Hash 对象,其中每对连续参数都已成为一个键值条目

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

如果参数列表不符合上述任何条件,则引发异常。

static VALUE
rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
{
    VALUE hash, tmp;

    if (argc == 1) {
        tmp = rb_hash_s_try_convert(Qnil, argv[0]);
        if (!NIL_P(tmp)) {
            if (!RHASH_EMPTY_P(tmp)  && rb_hash_compare_by_id_p(tmp)) {
                /* hash_copy for non-empty hash will copy compare_by_identity
                   flag, but we don't want it copied. Work around by
                   converting hash to flattened array and using that. */
                tmp = rb_hash_to_a(tmp);
            }
            else {
                hash = hash_alloc(klass);
                if (!RHASH_EMPTY_P(tmp))
                    hash_copy(hash, tmp);
                return hash;
            }
        }
        else {
            tmp = rb_check_array_type(argv[0]);
        }

        if (!NIL_P(tmp)) {
            long i;

            hash = hash_alloc(klass);
            for (i = 0; i < RARRAY_LEN(tmp); ++i) {
                VALUE e = RARRAY_AREF(tmp, i);
                VALUE v = rb_check_array_type(e);
                VALUE key, val = Qnil;

                if (NIL_P(v)) {
                    rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)",
                             rb_builtin_class_name(e), i);
                }
                switch (RARRAY_LEN(v)) {
                  default:
                    rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)",
                             RARRAY_LEN(v));
                  case 2:
                    val = RARRAY_AREF(v, 1);
                  case 1:
                    key = RARRAY_AREF(v, 0);
                    rb_hash_aset(hash, key, val);
                }
            }
            return hash;
        }
    }
    if (argc % 2 != 0) {
        rb_raise(rb_eArgError, "odd number of arguments for Hash");
    }

    hash = hash_alloc(klass);
    rb_hash_bulk_insert(argc, argv, hash);
    hash_verify(hash);
    return hash;
}
new(default_value = nil) → new_hash 单击以切换源
new {|hash, key| ... } → new_hash

返回一个新的空 Hash 对象。

新哈希的初始默认值和初始默认过程取决于上面使用了哪种形式。请参阅 默认值

如果没有给定参数或块,则将默认值和默认过程都初始化为 nil

h = Hash.new
h.default # => nil
h.default_proc # => nil

如果给定了参数 default_value 但没有给定块,则将默认值初始化为给定的 default_value,将默认过程初始化为 nil

h = Hash.new(false)
h.default # => false
h.default_proc # => nil

如果给定了块但没有给定参数,则将块存储为默认过程,并将默认值设置为 nil

h = Hash.new {|hash, key| "Default value for #{key}" }
h.default # => nil
h.default_proc.class # => Proc
h[:nosuch] # => "Default value for nosuch"
static VALUE
rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
{
    rb_hash_modify(hash);

    if (rb_block_given_p()) {
        rb_check_arity(argc, 0, 0);
        SET_PROC_DEFAULT(hash, rb_block_proc());
    }
    else {
        rb_check_arity(argc, 0, 1);

        VALUE options, ifnone;
        rb_scan_args(argc, argv, "01:", &ifnone, &options);
        if (NIL_P(ifnone) && !NIL_P(options)) {
            ifnone = options;
            rb_warn_deprecated_to_remove("3.4", "Calling Hash.new with keyword arguments", "Hash.new({ key: value })");
        }
        RHASH_SET_IFNONE(hash, ifnone);
    }

    return hash;
}
ruby2_keywords_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);
    }
}
哈希表[键] = 值 → 值 点击切换源代码

将给定的与给定的关联;返回

如果给定的存在,则用给定的替换其值;顺序不受影响(请参阅条目顺序

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

如果不存在,则添加;新条目按顺序排列在最后(请参阅条目顺序

h = {foo: 0, bar: 1}
h[:baz] = 2 # => 2
h.store(:bat, 3) # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
    bool iter_p = hash_iterating_p(hash);

    rb_hash_modify(hash);

    if (RHASH_TYPE(hash) == &identhash || rb_obj_class(key) != rb_cString) {
        RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val);
    }
    else {
        RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val);
    }
    return val;
}
别名: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) → 新数组或 nil 点击切换源代码

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

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

如果找不到键,则返回nil

static VALUE
rb_hash_assoc(VALUE hash, VALUE key)
{
    VALUE args[2];

    if (RHASH_EMPTY_P(hash)) return Qnil;

    if (RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type != &identhash) {
        VALUE value = Qundef;
        st_table assoctable = *RHASH_ST_TABLE(hash);
        assoctable.type = &(struct st_hash_type){
            .compare = assoc_cmp,
            .hash = assoctable.type->hash,
        };
        VALUE arg = (VALUE)&(struct assoc_arg){
            .tbl = &assoctable,
            .key = (st_data_t)key,
        };

        if (RB_OBJ_FROZEN(hash)) {
            value = assoc_lookup(arg);
        }
        else {
            hash_iter_lev_inc(hash);
            value = rb_ensure(assoc_lookup, arg, hash_foreach_ensure, hash);
        }
        hash_verify(hash);
        if (!UNDEF_P(value)) return rb_assoc_new(key, value);
    }

    args[0] = key;
    args[1] = Qnil;
    rb_hash_foreach(hash, assoc_i, (VALUE)args);
    return args[1];
}
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 → 新哈希表 点击切换源代码

返回一个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 → 对象 单击以切换源
default(key) → 对象

返回给定 key 的默认值。返回值将由默认过程或默认值确定。请参阅 默认值

如果没有参数,则返回当前默认值

h = {}
h.default # => nil

如果给出了 key,则返回 key 的默认值,无论该键是否存在

h = Hash.new { |hash, key| hash[key] = "No key #{key}"}
h[:foo] = "Hello"
h.default(:foo) # => "No key foo"
static VALUE
rb_hash_default(int argc, VALUE *argv, VALUE hash)
{
    VALUE ifnone;

    rb_check_arity(argc, 0, 1);
    ifnone = RHASH_IFNONE(hash);
    if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
        if (argc == 0) return Qnil;
        return call_default_proc(ifnone, hash, argv[0]);
    }
    return ifnone;
}
default = value → 对象 单击以切换源

将默认值设置为 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 → 过程或 nil 单击以切换源

返回 self 的默认过程(请参阅 默认值

h = {}
h.default_proc # => nil
h.default_proc = proc {|hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
static VALUE
rb_hash_default_proc(VALUE hash)
{
    if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
        return RHASH_IFNONE(hash);
    }
    return Qnil;
}
default_proc = proc → 过程 单击以切换源

self 的默认过程设置为 proc:(请参阅 默认值

h = {}
h.default_proc # => nil
h.default_proc = proc { |hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
h.default_proc = nil
h.default_proc # => nil
VALUE
rb_hash_set_default_proc(VALUE hash, VALUE proc)
{
    VALUE b;

    rb_hash_modify_check(hash);
    if (NIL_P(proc)) {
        SET_DEFAULT(hash, proc);
        return proc;
    }
    b = rb_check_convert_type_with_id(proc, T_DATA, "Proc", idTo_proc);
    if (NIL_P(b) || !rb_obj_is_proc(b)) {
        rb_raise(rb_eTypeError,
                 "wrong default_proc type %s (expected Proc)",
                 rb_obj_classname(proc));
    }
    proc = b;
    SET_PROC_DEFAULT(hash, proc);
    return proc;
}
delete(key) → 值或 nil 单击以切换源
delete(key) {|key| ... } → 对象

删除给定 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 → 新枚举器

如果给出了块,则使用每个键值对调用该块;删除块返回真值的所有条目;返回 self

h = {foo: 0, bar: 1, baz: 2}
h.delete_if {|key, value| value > 0 } # => {:foo=>0}

如果未给出块,则返回一个新的枚举器

h = {foo: 0, bar: 1, baz: 2}
e = h.delete_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:delete_if>
e.each { |key, value| value > 0 } # => {:foo=>0}
VALUE
rb_hash_delete_if(VALUE hash)
{
    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
    rb_hash_modify_check(hash);
    if (!RHASH_TABLE_EMPTY_P(hash)) {
        rb_hash_foreach(hash, delete_if_i, hash);
        compact_after_delete(hash);
    }
    return hash;
}
dig(key, *identifiers) → 对象 单击以切换源

查找并返回嵌套对象中由 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 {|key, value| ... } → self 单击以切换源
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 或 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 或 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 单击以切换源

返回一个新的哈希,其中不包括给定 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
别名:select
filter!
别名: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 哈希码。

如果两个哈希对象的内容相同(不考虑顺序),则它们具有相同的哈希码

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
别名: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 点击切换源

返回一个包含 self 中所有键的新 Array

h = {foo: 0, bar: 1, baz: 2}
h.keys # => [:foo, :bar, :baz]
VALUE
rb_hash_keys(VALUE hash)
{
    st_index_t size = RHASH_SIZE(hash);
    VALUE keys =  rb_ary_new_capa(size);

    if (size == 0) return keys;

    if (ST_DATA_COMPATIBLE_P(VALUE)) {
        RARRAY_PTR_USE(keys, ptr, {
            if (RHASH_AR_TABLE_P(hash)) {
                size = ar_keys(hash, ptr, size);
            }
            else {
                st_table *table = RHASH_ST_TABLE(hash);
                size = st_keys(table, ptr, size);
            }
        });
        rb_gc_writebarrier_remember(keys);
        rb_ary_set_len(keys, size);
    }
    else {
        rb_hash_foreach(hash, keys_i, keys);
    }

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

返回通过将每个 other_hashes 合并到 self 的副本中形成的新 Hash。

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


带参数且不带块

  • 返回通过将 other_hashes 中的每个连续 Hash 合并到 self 中形成的新 Hash 对象。

  • 每个新键条目都添加到末尾。

  • 每个重复键条目的值都会覆盖前一个值。

示例

h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h.merge(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}

带参数和块

  • 返回一个新的 Hash 对象,它是 self 和每个给定哈希的合并。

  • 给定的哈希从左到右合并。

  • 每个新键条目都添加到末尾。

  • 对于每个重复的键

    • 使用键以及旧值和新值调用该块。

    • 该块的返回值成为该条目的新值。

示例

h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h3 = h.merge(h1, h2) { |key, old_value, new_value| old_value + new_value }
h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}

不带参数

  • 返回 self 的副本。

  • 如果给出了块,则忽略该块。

示例

h = {foo: 0, bar: 1, baz: 2}
h.merge # => {:foo=>0, :bar=>1, :baz=>2}
h1 = h.merge { |key, old_value, new_value| raise 'Cannot happen' }
h1 # => {:foo=>0, :bar=>1, :baz=>2}
static VALUE
rb_hash_merge(int argc, VALUE *argv, VALUE self)
{
    return rb_hash_update(argc, argv, copy_compare_by_id(rb_hash_dup(self), self));
}
merge! → self
merge!(*other_hashes) → self
merge!(*other_hashes) { |key, old_value, new_value| ... } → self

将每个 other_hashes 合并到 self 中;返回 self

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

带参数且不带块

  • 返回 self,在给定的哈希合并到其中之后。

  • 给定的哈希从左到右合并。

  • 每个新条目都添加到末尾。

  • 每个重复键条目的值都会覆盖前一个值。

示例

h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h.merge!(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}

带参数和块

  • 返回 self,在给定的哈希合并之后。

  • 给定的哈希从左到右合并。

  • 每个新键条目都添加到末尾。

  • 对于每个重复的键

    • 使用键以及旧值和新值调用该块。

    • 该块的返回值成为该条目的新值。

示例

h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h3 = h.merge!(h1, h2) { |key, old_value, new_value| old_value + new_value }
h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}

不带参数

  • 返回 self,未修改。

  • 如果给出了块,则忽略该块。

示例

h = {foo: 0, bar: 1, baz: 2}
h.merge # => {:foo=>0, :bar=>1, :baz=>2}
h1 = h.merge! { |key, old_value, new_value| raise 'Cannot happen' }
h1 # => {:foo=>0, :bar=>1, :baz=>2}
别名:update
rassoc(value) → new_array or nil 单击以切换源

返回一个新的 2 元素 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 单击以切换源

通过重新计算每个键的哈希索引来重建哈希表;返回 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 单击以切换源
reject → new_enumerator

返回一个新的哈希对象,其条目全部来自 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 单击以切换源
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 单击以切换源
select → new_enumerator

返回一个新的哈希对象,其条目是该块返回真值条目的条目

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 or nil 单击以切换源
select! → new_enumerator

返回 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] or 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 → integer 点击切换源代码

返回 self 中条目的数量

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

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

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

忽略任何未找到的给定 keys

static VALUE
rb_hash_slice(int argc, VALUE *argv, VALUE hash)
{
    int i;
    VALUE key, value, result;

    if (argc == 0 || RHASH_EMPTY_P(hash)) {
        return copy_compare_by_id(rb_hash_new(), hash);
    }
    result = copy_compare_by_id(rb_hash_new_with_size(argc), hash);

    for (i = 0; i < argc; i++) {
        key = argv[i];
        value = rb_hash_lookup2(hash, key, Qundef);
        if (!UNDEF_P(value))
            rb_hash_aset(result, key, value);
    }

    return result;
}
store(key, value)

将给定的与给定的关联;返回

如果给定的存在,则用给定的替换其值;顺序不受影响(请参阅条目顺序

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

如果不存在,则添加;新条目按顺序排列在最后(请参阅条目顺序

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

返回一个包含 2 元素Array对象的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 or new_hash 点击切换源代码
to_h {|key, value| ... } → new_hash

对于 Hash 实例,返回self

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

当给定一个块时,返回一个内容基于该块的新 Hash 对象;该块应返回一个指定要包含在返回的 Array 中的键值对的 2 元素Array对象

h = {foo: 0, bar: 1, baz: 2}
h1 = h.to_h {|key, value| [value, key] }
h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
static VALUE
rb_hash_to_h(VALUE hash)
{
    if (rb_block_given_p()) {
        return rb_hash_to_h_block(hash);
    }
    if (rb_obj_class(hash) != rb_cHash) {
        const VALUE flags = RBASIC(hash)->flags;
        hash = hash_dup(hash, rb_cHash, flags & RHASH_PROC_DEFAULT);
    }
    return hash;
}
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
别名:inspect
transform_keys {|key| ... } → new_hash 点击切换源代码
transform_keys(hash2) → new_hash
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;
}
更新
别名:merge!
value?(value) → true 或 false

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

别名:has_value?
values → new_array 单击以切换源

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

h = {foo: 0, bar: 1, baz: 2}
h.values # => [0, 1, 2]
VALUE
rb_hash_values(VALUE hash)
{
    VALUE values;
    st_index_t size = RHASH_SIZE(hash);

    values = rb_ary_new_capa(size);
    if (size == 0) return values;

    if (ST_DATA_COMPATIBLE_P(VALUE)) {
        if (RHASH_AR_TABLE_P(hash)) {
            rb_gc_writebarrier_remember(values);
            RARRAY_PTR_USE(values, ptr, {
                size = ar_values(hash, ptr, size);
            });
        }
        else if (RHASH_ST_TABLE_P(hash)) {
            st_table *table = RHASH_ST_TABLE(hash);
            rb_gc_writebarrier_remember(values);
            RARRAY_PTR_USE(values, ptr, {
                size = st_values(table, ptr, size);
            });
        }
        rb_ary_set_len(values, size);
    }

    else {
        rb_hash_foreach(hash, values_i, values);
    }

    return values;
}
values_at(*keys) → new_array 单击以切换源

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

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

对于任何找不到的键,将返回 默认值

h.values_at(:hello, :foo) # => [nil, 0]
static VALUE
rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
{
    VALUE result = rb_ary_new2(argc);
    long i;

    for (i=0; i<argc; i++) {
        rb_ary_push(result, rb_hash_aref(hash, argv[i]));
    }
    return result;
}