類別 Hash

Hash 將其每個唯一的鍵對應到特定值。

Hash 與 陣列 有某些相似之處,但

Hash 資料語法

較舊的 Hash 資料語法使用「雜湊箭頭」,=>

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

或者,但僅適用於 Symbol 的 Hash 鍵,您可以使用較新的 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}

常見用途

您可以使用 Hash 為物件命名

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

您可以使用 Hash 為方法引數命名

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

注意:當方法呼叫中的最後一個引數為 Hash 時,可以省略大括號

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

您可以使用 Hash 初始化物件

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

建立 Hash

您可以使用下列方式明確建立 Hash 物件

您可以使用下列方式將特定物件轉換為雜湊

您可以透過呼叫方法 Hash.new 來建立 Hash。

建立一個空的 Hash

h = Hash.new
h # => {}
h.class # => Hash

您可以透過呼叫方法 Hash.[] 來建立 Hash。

建立一個空的 Hash

h = Hash[]
h # => {}

建立一個具有初始條目的 Hash

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

您可以使用文字形式(大括號)建立 Hash。

建立一個空的 Hash

h = {}
h # => {}

建立一個具有初始條目的 Hash

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

Hash 值基礎

擷取 Hash 值的最簡單方式(實例方法 []

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

建立或更新 Hash 值的最簡單方式(實例方法 []=

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}

刪除 Hash 條目的最簡單方式(實例方法 delete

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

條目順序

Hash 物件會按建立順序顯示其條目。這可以在下列情況中看到

新的 Hash 會根據給定的條目進行初始排序

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

新的條目會新增到最後面

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

更新值不會影響順序

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

但重新建立已刪除的項目可能會影響順序

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

雜湊金鑰

雜湊金鑰等效性

當物件的 hash 值相同且這兩個物件彼此 eql? 時,這兩個物件會被視為相同的雜湊金鑰。

修改正在使用的雜湊金鑰

在雜湊金鑰使用中進行修改會損壞雜湊的索引。

這個雜湊的金鑰是陣列

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

修改陣列元素 a0[0] 會變更它的雜湊值

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

並損壞雜湊索引

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

你可以使用 rehash 方法修復雜湊索引

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

字串 金鑰總是安全的。這是因為傳遞未凍結的 字串 作為金鑰時,會將它替換為重複的凍結字串

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

使用者定義的雜湊金鑰

物件必須實作 hasheql? 方法才能用作雜湊金鑰。注意:如果雜湊使用 compare_by_identity,則此需求不適用,因為比較會根據金鑰的物件 ID 而不是 hasheql? 進行。

物件 定義 hasheq? 的基本實作,讓每個物件成為一個不同的金鑰。通常,使用者定義的類別會想要覆寫這些方法以提供有意義的行為,或例如繼承具有這些方法的有用定義的 結構

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 的方法

設定 Hash 狀態的方法

查詢的方法

比較方法

擷取方法

指定方法

刪除方法

這些方法會從 self 中移除項目

這些方法會傳回移除某些項目的 self 副本

反覆運算方法

轉換方法

轉換金鑰與值的函式

其他函式

公開類別函式

Hash[] → new_empty_hash 按一下以切換原始碼
Hash[hash] → new_hash
Hash[ [*2_element_arrays] ] → new_hash
Hash[*objects] → new_hash

傳回一個新的雜湊物件,並填入任何給定的物件。請參閱 Hash::new

如果沒有參數,則傳回一個新的空雜湊。

當單一給定參數為雜湊時,傳回一個新的雜湊,並填入來自給定雜湊的項目,不包括預設值或程序。

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

當單一給定參數為 2 元素陣列的 陣列 時,傳回一個新的雜湊物件,其中每個 2 元素陣列形成一個金鑰值項目

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

當參數數量為偶數時,傳回一個新的雜湊物件,其中每一個連續的參數對都已成為一個金鑰值項目

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

傳回一個新的空雜湊物件。

新雜湊的初始預設值和初始預設程序取決於上述使用哪一種形式。請參閱 預設值

如果沒有給定參數或區塊,則將預設值和預設程序都初始化為 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 or 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] → 值 按一下以切換來源

如果找到,傳回與給定 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] = 值 → 值 按一下以切換來源

將給定的 與給定的 key 關聯;傳回

如果給定的 key 存在,以給定的 取代其值;順序不受影響 (請參閱 項目順序)

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

如果 key 不存在,新增 key;新項目在順序中最後一個 (請參閱 項目順序)

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 而沒有區塊,則如果對於任何鍵 keyh.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 or 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 or 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 or 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 的預設值。傳回的值將由預設程序或預設值決定。請參閱 預設值

若無參數,傳回目前的預設值

h = {}
h.default # => nil

若有給定 key,傳回 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 的預設程序(請參閱 預設值

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:(請參閱 預設值

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

若給定區塊,則呼叫區塊並傳入每個 key-value 配對;刪除區塊傳回真值的所有項目;傳回 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 {|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 的 1 維平面化


預設情況下,不會平面化巢狀陣列

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
別名為: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 或 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 或 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 → 整數

傳回 self 中的項目數目

{foo: 0, bar: 1, baz: 2}.length # => 3
別名:size
member?(key) → true 或 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,此 Hash 是透過將每個 other_hashes 合併到 self 的副本中所形成。

other_hashes 中的每個參數都必須是 Hash。


有參數而沒有區塊

  • 傳回新的 Hash 物件,此物件是透過將 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}

有參數和區塊

  • 傳回新的 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 或 nil 按一下以切換來源

傳回新的 2 元素 Array,其中包含第一個找到的項目的金鑰和值,此項目的值等於 == 值 (請參閱 項目順序)

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 元素 陣列

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 的項目

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)

將給定的 與給定的 key 關聯;傳回

如果給定的 key 存在,以給定的 取代其值;順序不受影響 (請參閱 項目順序)

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

如果 key 不存在,新增 key;新項目在順序中最後一個 (請參閱 項目順序)

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 個元素的 陣列 物件;每個巢狀 陣列 都包含 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 或 new_hash 按一下以切換來源
to_h {|key, value| ... } → new_hash

對於 Hash 的執行個體,傳回 self

對於 Hash 的子類別,傳回一個新的 Hash,其中包含 self 的內容。

當提供區塊時,傳回一個新的 Hash 物件,其內容基於區塊;區塊應傳回一個 2 個元素的 陣列 物件,指定要包含在傳回陣列中的金鑰值對

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 的值。

可以提供一個選用的 hash 引數,以將金鑰對應至新的金鑰。任何未提供的金鑰都將使用提供的區塊對應,或者如果未提供區塊,則保持不變。

轉換金鑰

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 相同,但會修改接收器本身,而不是傳回新的 hash。

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 按一下以切換來源

傳回一個新的 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;
}