類別 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
。
您可以透過呼叫方法 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 物件會按建立順序顯示其條目。這可以在下列情況中看到
-
反覆運算方法,例如
each
、each_key
、each_pair
、each_value
。 -
其他對順序敏感的方法,例如
shift
、keys
、values
。 -
方法
inspect
傳回的String
。
新的 Hash 會根據給定的條目進行初始排序
h = Hash[foo: 0, bar: 1] h # => {:foo=>0, :bar=>1}
新的條目會新增到最後面
h[:baz] = 2 h # => {:foo=>0, :bar=>1, :baz=>2}
更新值不會影響順序
h[:baz] = 3 h # => {:foo=>0, :bar=>1, :baz=>3}
但重新建立已刪除的項目可能會影響順序
h.delete(:foo) h[:foo] = 5 h # => {:bar=>1, :baz=>3, :foo=>5}
雜湊金鑰¶ ↑
雜湊金鑰等效性¶ ↑
當物件的 hash
值相同且這兩個物件彼此 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
使用者定義的雜湊金鑰¶ ↑
物件必須實作 hash
和 eql?
方法才能用作雜湊金鑰。注意:如果雜湊使用 compare_by_identity
,則此需求不適用,因為比較會根據金鑰的物件 ID 而不是 hash
和 eql?
進行。
物件
定義 hash
和 eq?
的基本實作,讓每個物件成為一個不同的金鑰。通常,使用者定義的類別會想要覆寫這些方法以提供有意義的行為,或例如繼承具有這些方法的有用定義的 結構
。
hash
的典型實作是根據物件的資料,而 eql?
通常會別名到覆寫的 ==
方法
class Book attr_reader :author, :title def initialize(author, title) @author = author @title = title end def ==(other) self.class === other && other.author == @author && other.title == @title end alias eql? == def hash [self.class, @author, @title].hash end end book1 = Book.new 'matz', 'Ruby in a Nutshell' book2 = Book.new 'matz', 'Ruby in a Nutshell' reviews = {} reviews[book1] = 'Great reference!' reviews[book2] = 'Nice and compact!' reviews.length #=> 1
預設值¶ ↑
方法 []
、values_at
和 dig
需要傳回與特定金鑰關聯的值。如果找不到該金鑰,則該值將由其預設程序(如果有)或其預設值(最初為「nil」)決定。
你可以使用 default
方法擷取預設值
h = Hash.new h.default # => nil
你可以透過將參數傳遞給 Hash.new
方法或使用 default=
方法來設定預設值
h = Hash.new(-1) h.default # => -1 h.default = 0 h.default # => 0
找不到金鑰時,這個預設值會傳回給 []
、values_at
和 dig
counts = {foo: 42} counts.default # => nil (default) counts[:foo] = 42 counts[:bar] # => nil counts.default = 0 counts[:bar] # => 0 counts.values_at(:foo, :bar, :baz) # => [42, 0, 0] counts.dig(:bar) # => 0
請注意,預設值會在未重複的情況下使用。不建議將預設值設定為可變動物件
synonyms = Hash.new([]) synonyms[:hello] # => [] synonyms[:hello] << :hi # => [:hi], but this mutates the default! synonyms.default # => [:hi] synonyms[:world] << :universe synonyms[:world] # => [:hi, :universe], oops synonyms.keys # => [], oops
若要將可變動物件用作預設值,建議使用預設程序
預設 Proc
¶ ↑
當 Hash 的預設程序設定(即非 nil
)時,方法 []
傳回的預設值將僅由預設程序決定。
您可以使用 default_proc
方法來擷取預設程序。
h = Hash.new h.default_proc # => nil
您可以透過呼叫帶有區塊的 Hash.new
或呼叫 default_proc=
方法來設定預設程序。
h = Hash.new { |hash, key| "Default value for #{key}" } h.default_proc.class # => Proc h.default_proc = proc { |hash, key| "Default value for #{key.inspect}" } h.default_proc.class # => Proc
當預設程序設定(即非 nil
)且方法 []
呼叫時,會傳入不存在的鍵值,[]
會呼叫預設程序,同時傳入 Hash 物件本身和遺失的鍵值,然後傳回程序的傳回值。
h = Hash.new { |hash, key| "Default value for #{key}" } h[:nosuch] # => "Default value for nosuch"
請注意,在上述範例中,並未建立鍵值 :nosuch
的項目。
h.include?(:nosuch) # => false
不過,程序本身可以新增新項目。
synonyms = Hash.new { |hash, key| hash[key] = [] } synonyms.include?(:hello) # => false synonyms[:hello] << :hi # => [:hi] synonyms[:world] << :universe # => [:universe] synonyms.keys # => [:hello, :world]
請注意,設定預設程序會清除預設值,反之亦然。
請注意,修改雜湊的預設程序在多執行緒同時呼叫相同鍵值的預設程序時,並非執行緒安全的。
此處內容¶ ↑
首先,其他位置的內容。Hash 類別
-
繼承自 Object 類別。
-
包含 Enumerable 模組,提供數十種其他方法。
在此,Hash 類別提供對下列項目有用的方法:
Hash 類別也包含 Enumerable
模組的方法。
建立 Hash 的方法¶ ↑
-
::[]
:傳回一個使用指定物件填入的新雜湊。 -
::new
:傳回一個新的空雜湊。 -
::try_convert
:傳回從指定物件建立的新雜湊。
設定 Hash 狀態的方法¶ ↑
-
compare_by_identity
:設定self
,在比較鍵值時只考慮身分。 -
default=
:設定預設值為指定值。 -
default_proc=
:設定預設程序為指定程序。 -
rehash
:透過重新計算每個鍵值的雜湊索引,重建雜湊表。
查詢的方法¶ ↑
-
any?
:傳回任何元素是否符合給定條件。 -
compare_by_identity?
:傳回雜湊在比較金鑰時是否只考慮身分。 -
default
:傳回預設值,或給定金鑰的預設值。 -
default_proc
:傳回預設程序。 -
empty?
:傳回是否沒有任何項目。 -
eql?
:傳回給定物件是否等於self
。 -
hash
:傳回整數雜湊碼。 -
has_value?
:傳回給定物件是否為self
中的值。 -
value?
:傳回給定物件是否為self
中的值。
比較方法¶ ↑
-
<
:傳回self
是否為給定物件的真子集。 -
<=
:傳回self
是否為給定物件的子集。 -
==
:傳回給定物件是否等於self
。 -
>
:傳回self
是否為給定物件的真超集。 -
>=
:傳回self
是否為給定物件的超集。
擷取方法¶ ↑
-
[]
:傳回與給定金鑰關聯的值。 -
assoc
:傳回包含給定金鑰及其值的 2 元素陣列。 -
dig
:傳回嵌套物件中由給定金鑰和額外引數指定之物件。 -
fetch
:傳回給定金鑰的值。 -
fetch_values
:傳回包含與給定金鑰關聯之值的陣列。 -
key
:傳回具有給定值的第一個找到項目的金鑰。 -
keys
:傳回包含self
中所有金鑰的陣列。 -
rassoc
:傳回包含具有給定值的第一個找到項目的金鑰和值的 2 元素陣列。 -
values
:傳回包含self
中所有值的陣列。 -
values_at
:傳回包含給定金鑰之值的陣列。
指定方法¶ ↑
刪除方法¶ ↑
這些方法會從 self
中移除項目
-
clear
:從self
中移除所有項目。 -
compact!
:從self
中移除所有nil
值的項目。 -
delete
:移除給定金鑰的項目。 -
delete_if
:移除由給定區塊選取的項目。 -
keep_if
:僅保留由給定區塊選取的項目。 -
reject!
:移除由給定區塊選取的項目。 -
shift
:移除並傳回第一個項目。
這些方法會傳回移除某些項目的 self
副本
-
compact
:傳回已移除所有nil
值項目的self
副本。 -
except
:傳回已移除指定金鑰項目的self
副本。 -
reject
:傳回已移除由給定區塊指定的項目的self
副本。 -
slice
:傳回包含給定金鑰項目的雜湊。
反覆運算方法¶ ↑
-
each_key
:對每個金鑰呼叫給定的區塊。 -
each_value
:對每個值呼叫給定的區塊。
轉換方法¶ ↑
-
to_a
:傳回包含 2 個元素陣列的新陣列;每個巢狀陣列包含來自self
的金鑰值對。 -
to_h
:如果為雜湊,則傳回self
;如果為雜湊的子類別,則傳回包含來自self
的項目的雜湊。 -
to_hash
:傳回self
。 -
to_proc
:傳回一個將給定金鑰對應到其值的程序。
轉換金鑰與值的函式¶ ↑
-
transform_keys
:傳回一個修改金鑰後的self
副本。 -
transform_keys!
:修改self
中的金鑰。 -
transform_values
:傳回一個修改值後的self
副本。 -
transform_values!
:修改self
中的值。
其他函式¶ ↑
公開類別函式
傳回一個新的雜湊物件,並填入任何給定的物件。請參閱 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; }
傳回一個新的空雜湊物件。
新雜湊的初始預設值和初始預設程序取決於上述使用哪一種形式。請參閱 預設值。
如果沒有給定參數或區塊,則將預設值和預設程序都初始化為 nil
h = Hash.new h.default # => nil h.default_proc # => nil
如果給定參數 default_value
但沒有給定區塊,則將預設值初始化為給定的 default_value
,並將預設程序初始化為 nil
h = Hash.new(false) h.default # => false h.default_proc # => nil
如果給定區塊但沒有給定參數,則將區塊儲存為預設程序,並將預設值設定為 nil
h = Hash.new {|hash, key| "Default value for #{key}" } h.default # => nil h.default_proc.class # => Proc h[:nosuch] # => "Default value for nosuch"
static VALUE rb_hash_initialize(int argc, VALUE *argv, VALUE hash) { rb_hash_modify(hash); if (rb_block_given_p()) { rb_check_arity(argc, 0, 0); SET_PROC_DEFAULT(hash, rb_block_proc()); } else { rb_check_arity(argc, 0, 1); VALUE options, ifnone; rb_scan_args(argc, argv, "01:", &ifnone, &options); if (NIL_P(ifnone) && !NIL_P(options)) { ifnone = options; rb_warn_deprecated_to_remove("3.4", "Calling Hash.new with keyword arguments", "Hash.new({ key: value })"); } RHASH_SET_IFNONE(hash, ifnone); } return hash; }
複製一個給定的雜湊,並新增一個 ruby2_keywords 旗標。此函式不適用於一般用途;用於除錯、研究和一些真正必要的案例,例如參數的反序列化。
h = {k: 1} h = Hash.ruby2_keywords_hash(h) def foo(k: 42) k end foo(*[h]) #=> 1 with neither a warning or an error
static VALUE rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash) { Check_Type(hash, T_HASH); VALUE tmp = rb_hash_dup(hash); if (RHASH_EMPTY_P(hash) && rb_hash_compare_by_id_p(hash)) { rb_hash_compare_by_id(tmp); } RHASH(tmp)->basic.flags |= RHASH_PASS_AS_KEYWORDS; return tmp; }
檢查給定的雜湊是否已由 Module#ruby2_keywords
(或 Proc#ruby2_keywords
)標記。此函式不適用於一般用途;用於除錯、研究和一些真正必要的案例,例如參數的序列化。
ruby2_keywords def foo(*args) Hash.ruby2_keywords_hash?(args.last) end foo(k: 1) #=> true foo({k: 1}) #=> false
static VALUE rb_hash_s_ruby2_keywords_hash_p(VALUE dummy, VALUE hash) { Check_Type(hash, T_HASH); return RBOOL(RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS); }
如果 obj
是 Hash 物件,傳回 obj
。
否則,如果 obj
回應 :to_hash
,呼叫 obj.to_hash
並傳回結果。
如果 obj
沒有回應 :to_hash
,傳回 nil
。
引發例外,除非 obj.to_hash
傳回 Hash 物件。
static VALUE rb_hash_s_try_convert(VALUE dummy, VALUE hash) { return rb_check_hash_type(hash); }
公開實例方法
如果 hash
是 other_hash
的適當子集,傳回 true
,否則傳回 false
。
h1 = {foo: 0, bar: 1} h2 = {foo: 0, bar: 1, baz: 2} h1 < h2 # => true h2 < h1 # => false h1 < h1 # => false
static VALUE rb_hash_lt(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) >= RHASH_SIZE(other)) return Qfalse; return hash_le(hash, other); }
如果 hash
是 other_hash
的子集,傳回 true
,否則傳回 false
。
h1 = {foo: 0, bar: 1} h2 = {foo: 0, bar: 1, baz: 2} h1 <= h2 # => true h2 <= h1 # => false h1 <= h1 # => true
static VALUE rb_hash_le(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) > RHASH_SIZE(other)) return Qfalse; return hash_le(hash, other); }
如果下列所有條件都成立,傳回 true
。
-
object
是 Hash 物件。 -
hash
和object
有相同的鍵 (不論順序)。 -
對於每個鍵
key
,hash[key] == object[key]
。
否則,傳回 false
。
相等
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1, baz: 2} h1 == h2 # => true h3 = {baz: 2, bar: 1, foo: 0} h1 == h3 # => true
static VALUE rb_hash_equal(VALUE hash1, VALUE hash2) { return hash_equal(hash1, hash2, FALSE); }
如果 hash
是 other_hash
的適當超集,傳回 true
,否則傳回 false
。
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1} h1 > h2 # => true h2 > h1 # => false h1 > h1 # => false
static VALUE rb_hash_gt(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) <= RHASH_SIZE(other)) return Qfalse; return hash_le(other, hash); }
如果 hash
是 other_hash
的超集,傳回 true
,否則傳回 false
。
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1} h1 >= h2 # => true h2 >= h1 # => false h1 >= h1 # => true
static VALUE rb_hash_ge(VALUE hash, VALUE other) { other = to_hash(other); if (RHASH_SIZE(hash) < RHASH_SIZE(other)) return Qfalse; return hash_le(other, hash); }
如果找到,傳回與給定 key
關聯的值。
h = {foo: 0, bar: 1, baz: 2} h[:foo] # => 0
如果找不到 key
,傳回預設值 (請參閱 預設值)
h = {foo: 0, bar: 1, baz: 2} h[:nosuch] # => nil
VALUE rb_hash_aref(VALUE hash, VALUE key) { st_data_t val; if (hash_stlike_lookup(hash, key, &val)) { return (VALUE)val; } else { return rb_hash_default_value(hash, key); } }
將給定的 值
與給定的 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; }
如果任何元素滿足給定的條件,則傳回 true
;否則傳回 false
。
如果 self
沒有元素,則傳回 false
,且不會使用參數或區塊。
如果沒有參數和區塊,則如果 self
非空,則傳回 true
;如果為空,則傳回 false
。
如果具有參數 object
而沒有區塊,則如果對於任何鍵 key
,h.assoc(key) == object
,則傳回 true
h = {foo: 0, bar: 1, baz: 2} h.any?([:bar, 1]) # => true h.any?([:bar, 0]) # => false h.any?([:baz, 1]) # => false
如果沒有參數而有區塊,則使用每個鍵值對呼叫區塊;如果區塊傳回任何真值,則傳回 true
,否則傳回 false
h = {foo: 0, bar: 1, baz: 2} h.any? {|key, value| value < 3 } # => true h.any? {|key, value| value > 3 } # => false
static VALUE rb_hash_any_p(int argc, VALUE *argv, VALUE hash) { VALUE args[2]; args[0] = Qfalse; rb_check_arity(argc, 0, 1); if (RHASH_EMPTY_P(hash)) return Qfalse; if (argc) { if (rb_block_given_p()) { rb_warn("given block not used"); } args[1] = argv[0]; rb_hash_foreach(hash, any_p_i_pattern, (VALUE)args); } else { if (!rb_block_given_p()) { /* yields pairs, never false */ return Qtrue; } if (rb_block_pair_yield_optimizable()) rb_hash_foreach(hash, any_p_i_fast, (VALUE)args); else rb_hash_foreach(hash, any_p_i, (VALUE)args); } return args[0]; }
如果找到給定的 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]; }
移除所有雜湊項目;傳回 self
。
VALUE rb_hash_clear(VALUE hash) { rb_hash_modify_check(hash); if (hash_iterating_p(hash)) { rb_hash_foreach(hash, clear_i, 0); } else if (RHASH_AR_TABLE_P(hash)) { ar_clear(hash); } else { st_clear(RHASH_ST_TABLE(hash)); compact_after_delete(hash); } return hash; }
傳回 self
的副本,其中已移除所有 nil
值的項目
h = {foo: 0, bar: nil, baz: 2, bat: nil} h1 = h.compact h1 # => {:foo=>0, :baz=>2}
static VALUE rb_hash_compact(VALUE hash) { VALUE result = rb_hash_dup(hash); if (!RHASH_EMPTY_P(hash)) { rb_hash_foreach(result, delete_if_nil, result); compact_after_delete(result); } else if (rb_hash_compare_by_id_p(hash)) { result = rb_hash_compare_by_id(result); } return result; }
傳回 self
,其中已移除所有 nil
值的項目(就地)
h = {foo: 0, bar: nil, baz: 2, bat: nil} h.compact! # => {:foo=>0, :baz=>2}
如果未移除任何項目,則傳回 nil
。
static VALUE rb_hash_compact_bang(VALUE hash) { st_index_t n; rb_hash_modify_check(hash); n = RHASH_SIZE(hash); if (n) { rb_hash_foreach(hash, delete_if_nil, hash); if (n != RHASH_SIZE(hash)) return hash; } return Qnil; }
設定 self
在比較鍵時僅考慮身分;只有當兩個鍵是同一個物件時,才會將它們視為相同;傳回 self
。
預設情況下,這兩個物件會被視為同一個鍵,因此 s1
會覆寫 s0
s0 = 'x' s1 = 'x' h = {} h.compare_by_identity? # => false h[s0] = 0 h[s1] = 1 h # => {"x"=>1}
在呼叫 #compare_by_identity 之後,這些鍵會被視為不同,因此不會互相覆寫
h = {} h.compare_by_identity # => {} h.compare_by_identity? # => true h[s0] = 0 h[s1] = 1 h # => {"x"=>0, "x"=>1}
VALUE rb_hash_compare_by_id(VALUE hash) { VALUE tmp; st_table *identtable; if (rb_hash_compare_by_id_p(hash)) return hash; rb_hash_modify_check(hash); if (hash_iterating_p(hash)) { rb_raise(rb_eRuntimeError, "compare_by_identity during iteration"); } if (RHASH_TABLE_EMPTY_P(hash)) { // Fast path: There's nothing to rehash, so we don't need a `tmp` table. // We're most likely an AR table, so this will need an allocation. ar_force_convert_table(hash, __FILE__, __LINE__); HASH_ASSERT(RHASH_ST_TABLE_P(hash)); RHASH_ST_TABLE(hash)->type = &identhash; } else { // Slow path: Need to rehash the members of `self` into a new // `tmp` table using the new `identhash` compare/hash functions. tmp = hash_alloc(0); hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash)); identtable = RHASH_ST_TABLE(tmp); rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); rb_hash_free(hash); // We know for sure `identtable` is an st table, // so we can skip `ar_force_convert_table` here. RHASH_ST_TABLE_SET(hash, identtable); RHASH_ST_CLEAR(tmp); } return hash; }
如果已呼叫 compare_by_identity
,則傳回 true
,否則傳回 false
。
VALUE rb_hash_compare_by_id_p(VALUE hash) { return RBOOL(RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type == &identhash); }
傳回給定 key
的預設值。傳回的值將由預設程序或預設值決定。請參閱 預設值。
若無參數,傳回目前的預設值
h = {} h.default # => nil
若有給定 key
,傳回 key
的預設值,不論該 key 是否存在
h = Hash.new { |hash, key| hash[key] = "No key #{key}"} h[:foo] = "Hello" h.default(:foo) # => "No key foo"
static VALUE rb_hash_default(int argc, VALUE *argv, VALUE hash) { VALUE ifnone; rb_check_arity(argc, 0, 1); ifnone = RHASH_IFNONE(hash); if (FL_TEST(hash, RHASH_PROC_DEFAULT)) { if (argc == 0) return Qnil; return call_default_proc(ifnone, hash, argv[0]); } return ifnone; }
將預設值設定為 value
;傳回 value
h = {} h.default # => nil h.default = false # => false h.default # => false
請參閱 預設值。
static VALUE rb_hash_set_default(VALUE hash, VALUE ifnone) { rb_hash_modify_check(hash); SET_DEFAULT(hash, ifnone); return ifnone; }
傳回 self
的預設程序(請參閱 預設值)
h = {} h.default_proc # => nil h.default_proc = proc {|hash, key| "Default value for #{key}" } h.default_proc.class # => Proc
static VALUE rb_hash_default_proc(VALUE hash) { if (FL_TEST(hash, RHASH_PROC_DEFAULT)) { return RHASH_IFNONE(hash); } return Qnil; }
將 self
的預設程序設定為 proc
:(請參閱 預設值)
h = {} h.default_proc # => nil h.default_proc = proc { |hash, key| "Default value for #{key}" } h.default_proc.class # => Proc h.default_proc = nil h.default_proc # => nil
VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc) { VALUE b; rb_hash_modify_check(hash); if (NIL_P(proc)) { SET_DEFAULT(hash, proc); return proc; } b = rb_check_convert_type_with_id(proc, T_DATA, "Proc", idTo_proc); if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, "wrong default_proc type %s (expected Proc)", rb_obj_classname(proc)); } proc = b; SET_PROC_DEFAULT(hash, proc); return proc; }
刪除給定 key
的項目,並傳回其關聯值。
若未給定區塊且找到 key
,則刪除該項目並傳回關聯值
h = {foo: 0, bar: 1, baz: 2} h.delete(:bar) # => 1 h # => {:foo=>0, :baz=>2}
若未給定區塊且未找到 key
,則傳回 nil
。
若給定區塊且找到 key
,則略過區塊、刪除項目,並傳回關聯值
h = {foo: 0, bar: 1, baz: 2} h.delete(:baz) { |key| raise 'Will never happen'} # => 2 h # => {:foo=>0, :bar=>1}
若給定區塊且未找到 key
,則呼叫區塊並傳回區塊的傳回值
h = {foo: 0, bar: 1, baz: 2} h.delete(:nosuch) { |key| "Key #{key} not found" } # => "Key nosuch not found" h # => {:foo=>0, :bar=>1, :baz=>2}
static VALUE rb_hash_delete_m(VALUE hash, VALUE key) { VALUE val; rb_hash_modify_check(hash); val = rb_hash_delete_entry(hash, key); if (!UNDEF_P(val)) { compact_after_delete(hash); return val; } else { if (rb_block_given_p()) { return rb_yield(key); } else { return Qnil; } } }
若給定區塊,則呼叫區塊並傳入每個 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; }
在巢狀物件中尋找並傳回由 key
和 identifiers
指定的物件。巢狀物件可能是各種類別的執行個體。請參閱 Dig 方法。
嵌套雜湊
h = {foo: {bar: {baz: 2}}} h.dig(:foo) # => {:bar=>{:baz=>2}} h.dig(:foo, :bar) # => {:baz=>2} h.dig(:foo, :bar, :baz) # => 2 h.dig(:foo, :bar, :BAZ) # => nil
嵌套雜湊和陣列
h = {foo: {bar: [:a, :b, :c]}} h.dig(:foo, :bar, 2) # => :c
此方法會對不存在的鍵使用預設值
h = {foo: {bar: [:a, :b, :c]}} h.dig(:hello) # => nil h.default_proc = -> (hash, _key) { hash } h.dig(:hello, :world) # => h h.dig(:hello, :world, :foo, :bar, 2) # => :c
static VALUE rb_hash_dig(int argc, VALUE *argv, VALUE self) { rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); self = rb_hash_aref(self, *argv); if (!--argc) return self; ++argv; return rb_obj_dig(argc, argv, self, Qnil); }
呼叫給定區塊,並提供每個鍵值對;傳回 self
h = {foo: 0, bar: 1, baz: 2} h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
輸出
foo: 0 bar: 1 baz: 2
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair> h1 = e.each {|key, value| puts "#{key}: #{value}"} h1 # => {:foo=>0, :bar=>1, :baz=>2}
輸出
foo: 0 bar: 1 baz: 2
呼叫給定區塊,並提供每個鍵;傳回 self
h = {foo: 0, bar: 1, baz: 2} h.each_key {|key| puts key } # => {:foo=>0, :bar=>1, :baz=>2}
輸出
foo bar baz
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_key # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_key> h1 = e.each {|key| puts key } h1 # => {:foo=>0, :bar=>1, :baz=>2}
輸出
foo bar baz
static VALUE rb_hash_each_key(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_foreach(hash, each_key_i, 0); return hash; }
呼叫給定區塊,並提供每個鍵值對;傳回 self
h = {foo: 0, bar: 1, baz: 2} h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
輸出
foo: 0 bar: 1 baz: 2
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair> h1 = e.each {|key, value| puts "#{key}: #{value}"} h1 # => {:foo=>0, :bar=>1, :baz=>2}
輸出
foo: 0 bar: 1 baz: 2
static VALUE rb_hash_each_pair(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); if (rb_block_pair_yield_optimizable()) rb_hash_foreach(hash, each_pair_i_fast, 0); else rb_hash_foreach(hash, each_pair_i, 0); return hash; }
呼叫給定區塊,並提供每個值;傳回 self
h = {foo: 0, bar: 1, baz: 2} h.each_value {|value| puts value } # => {:foo=>0, :bar=>1, :baz=>2}
輸出
0 1 2
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.each_value # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_value> h1 = e.each {|value| puts value } h1 # => {:foo=>0, :bar=>1, :baz=>2}
輸出
0 1 2
static VALUE rb_hash_each_value(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_foreach(hash, each_value_i, 0); return hash; }
如果沒有雜湊項目,則傳回 true
,否則傳回 false
{}.empty? # => true {foo: 0, bar: 1, baz: 2}.empty? # => false
static VALUE rb_hash_empty_p(VALUE hash) { return RBOOL(RHASH_EMPTY_P(hash)); }
如果下列所有條件都成立,傳回 true
。
-
object
是 Hash 物件。 -
hash
和object
有相同的鍵 (不論順序)。 -
對於每個鍵
key
,h[key] eql? object[key]
。
否則,傳回 false
。
相等
h1 = {foo: 0, bar: 1, baz: 2} h2 = {foo: 0, bar: 1, baz: 2} h1.eql? h2 # => true h3 = {baz: 2, bar: 1, foo: 0} h1.eql? h3 # => true
static VALUE rb_hash_eql(VALUE hash1, VALUE hash2) { return hash_equal(hash1, hash2, TRUE); }
傳回新的雜湊,排除給定 keys
的項目
h = { a: 100, b: 200, c: 300 } h.except(:a) #=> {:b=>200, :c=>300}
任何未找到的給定 keys
都會被忽略。
static VALUE rb_hash_except(int argc, VALUE *argv, VALUE hash) { int i; VALUE key, result; result = hash_dup_with_compare_by_id(hash); for (i = 0; i < argc; i++) { key = argv[i]; rb_hash_delete(result, key); } compact_after_delete(result); return result; }
傳回給定 key
的值(如果找到的話)。
h = {foo: 0, bar: 1, baz: 2} h.fetch(:bar) # => 1
如果未找到 key
,且未提供區塊,則傳回 default_value
{}.fetch(:nosuch, :default) # => :default
如果未找到 key
,且提供了區塊,則將 key
傳遞給區塊,並傳回區塊的傳回值
{}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch"
如果未提供 default_value
或區塊,則引發 KeyError
。
請注意,此方法不會使用 default
或 default_proc
的值。
static VALUE rb_hash_fetch_m(int argc, VALUE *argv, VALUE hash) { VALUE key; st_data_t val; long block_given; rb_check_arity(argc, 1, 2); key = argv[0]; block_given = rb_block_given_p(); if (block_given && argc == 2) { rb_warn("block supersedes default value argument"); } if (hash_stlike_lookup(hash, key, &val)) { return (VALUE)val; } else { if (block_given) { return rb_yield(key); } else if (argc == 1) { VALUE desc = rb_protect(rb_inspect, key, 0); if (NIL_P(desc)) { desc = rb_any_to_s(key); } desc = rb_str_ellipsize(desc, 65); rb_key_err_raise(rb_sprintf("key not found: %"PRIsVALUE, desc), hash, key); } else { return argv[1]; } } }
傳回新的 Array
,其中包含與給定鍵 *keys 相關聯的值
h = {foo: 0, bar: 1, baz: 2} h.fetch_values(:baz, :foo) # => [2, 0]
如果未提供任何參數,則傳回新的空 Array
。
當給定一個區塊時,呼叫區塊並傳入每個遺失的鍵,並將區塊的回傳值視為該鍵的值
h = {foo: 0, bar: 1, baz: 2} values = h.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s} values # => [1, 0, "bad", "bam"]
當沒有給定區塊時,如果找不到任何給定的鍵,則會引發例外
static VALUE rb_hash_fetch_values(int argc, VALUE *argv, VALUE hash) { VALUE result = rb_ary_new2(argc); long i; for (i=0; i<argc; i++) { rb_ary_push(result, rb_hash_fetch(hash, argv[i])); } return result; }
傳回一個新的 Array
物件,該物件是 self
的 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; }
如果 value
是 self
中的值,則傳回 true
,否則傳回 false
。
static VALUE rb_hash_has_value(VALUE hash, VALUE val) { VALUE data[2]; data[0] = Qfalse; data[1] = val; rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data); return data[0]; }
傳回雜湊的 Integer
雜湊碼。
如果兩個 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); }
如果 key
是 self
中的鍵,則傳回 true
,否則傳回 false
。
VALUE rb_hash_has_key(VALUE hash, VALUE key) { return RBOOL(hash_stlike_lookup(hash, key, NULL)); }
傳回一個包含雜湊條目的新 String
h = {foo: 0, bar: 1, baz: 2} h.inspect # => "{:foo=>0, :bar=>1, :baz=>2}"
static VALUE rb_hash_inspect(VALUE hash) { if (RHASH_EMPTY_P(hash)) return rb_usascii_str_new2("{}"); return rb_exec_recursive(inspect_hash, hash, 0); }
傳回一個新的 Hash 物件,其中每個鍵值對都反轉
h = {foo: 0, bar: 1, baz: 2} h1 = h.invert h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
覆寫任何重複的新鍵:(請參閱 條目順序)
h = {foo: 0, bar: 0, baz: 0} h.invert # => {0=>:baz}
static VALUE rb_hash_invert(VALUE hash) { VALUE h = rb_hash_new_with_size(RHASH_SIZE(hash)); rb_hash_foreach(hash, rb_hash_invert_i, h); return h; }
呼叫每個鍵值對的區塊;如果區塊傳回真值,則保留條目;否則刪除條目;傳回 self
。
h = {foo: 0, bar: 1, baz: 2} h.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.keep_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:keep_if> e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
static VALUE rb_hash_keep_if(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { rb_hash_foreach(hash, keep_if_i, hash); } return hash; }
傳回具有給定 value
的第一個找到條目的鍵(請參閱 條目順序)
h = {foo: 0, bar: 2, baz: 2} h.key(0) # => :foo h.key(2) # => :bar
如果找不到此值,則傳回 nil
。
static VALUE rb_hash_key(VALUE hash, VALUE value) { VALUE args[2]; args[0] = value; args[1] = Qnil; rb_hash_foreach(hash, key_i, (VALUE)args); return args[1]; }
傳回包含 self
中所有金鑰的新 Array
h = {foo: 0, bar: 1, baz: 2} h.keys # => [:foo, :bar, :baz]
VALUE rb_hash_keys(VALUE hash) { st_index_t size = RHASH_SIZE(hash); VALUE keys = rb_ary_new_capa(size); if (size == 0) return keys; if (ST_DATA_COMPATIBLE_P(VALUE)) { RARRAY_PTR_USE(keys, ptr, { if (RHASH_AR_TABLE_P(hash)) { size = ar_keys(hash, ptr, size); } else { st_table *table = RHASH_ST_TABLE(hash); size = st_keys(table, ptr, size); } }); rb_gc_writebarrier_remember(keys); rb_ary_set_len(keys, size); } else { rb_hash_foreach(hash, keys_i, keys); } return keys; }
傳回新的 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)); }
將每個 other_hashes
合併到 self
中;傳回 self
。
other_hashes
中的每個參數都必須是 Hash。
有參數而沒有區塊
-
傳回
self
,在將給定的雜湊合併到其中之後。 -
給定的雜湊會從左到右合併。
-
每個新項目都會新增到最後面。
-
每個重複金鑰項目的值都會覆寫前一個值。
範例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h.merge!(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
有參數和區塊
-
傳回
self
,在合併給定的雜湊之後。 -
給定的雜湊會從左到右合併。
-
每個新金鑰項目都會新增到最後面。
-
對於每個重複金鑰
-
呼叫區塊,並提供金鑰和舊值和新值。
-
區塊的傳回值會成為該項目的新值。
-
範例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h3 = h.merge!(h1, h2) { |key, old_value, new_value| old_value + new_value } h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
沒有參數
-
傳回
self
,未修改。 -
如果給定了區塊,則會忽略該區塊。
範例
h = {foo: 0, bar: 1, baz: 2} h.merge # => {:foo=>0, :bar=>1, :baz=>2} h1 = h.merge! { |key, old_value, new_value| raise 'Cannot happen' } h1 # => {:foo=>0, :bar=>1, :baz=>2}
透過重新計算每個鍵的雜湊索引來重建雜湊表;傳回 self
。
如果在建立項目後,鍵的雜湊值已變更,則雜湊表會失效。請參閱 修改現用雜湊鍵。
VALUE rb_hash_rehash(VALUE hash) { VALUE tmp; st_table *tbl; if (hash_iterating_p(hash)) { rb_raise(rb_eRuntimeError, "rehash during iteration"); } rb_hash_modify_check(hash); if (RHASH_AR_TABLE_P(hash)) { tmp = hash_alloc(0); rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); hash_ar_free_and_clear_table(hash); ar_copy(hash, tmp); } else if (RHASH_ST_TABLE_P(hash)) { st_table *old_tab = RHASH_ST_TABLE(hash); tmp = hash_alloc(0); hash_st_table_init(tmp, old_tab->type, old_tab->num_entries); tbl = RHASH_ST_TABLE(tmp); rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); hash_st_free(hash); RHASH_ST_TABLE_SET(hash, tbl); RHASH_ST_CLEAR(tmp); } hash_verify(hash); return hash; }
傳回一個新的雜湊物件,其項目全部來自 self
,而區塊傳回 false
或 nil
h = {foo: 0, bar: 1, baz: 2} h1 = h.reject {|key, value| key.start_with?('b') } h1 # => {:foo=>0}
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.reject # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject> h1 = e.each {|key, value| key.start_with?('b') } h1 # => {:foo=>0}
static VALUE rb_hash_reject(VALUE hash) { VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); result = hash_dup_with_compare_by_id(hash); if (!RHASH_EMPTY_P(hash)) { rb_hash_foreach(result, delete_if_i, result); compact_after_delete(result); } return result; }
傳回 self
,其剩餘項目是區塊傳回 false
或 nil
的項目
h = {foo: 0, bar: 1, baz: 2} h.reject! {|key, value| value < 2 } # => {:baz=>2}
如果未移除任何項目,則傳回 nil
。
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.reject! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject!> e.each {|key, value| key.start_with?('b') } # => {:foo=>0}
static VALUE rb_hash_reject_bang(VALUE hash) { st_index_t n; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify(hash); n = RHASH_SIZE(hash); if (!n) return Qnil; rb_hash_foreach(hash, delete_if_i, hash); if (n == RHASH_SIZE(hash)) return Qnil; return hash; }
使用 other_hash
的內容取代 self
的全部內容;傳回 self
h = {foo: 0, bar: 1, baz: 2} h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4}
傳回一個新的雜湊物件,其項目是區塊傳回真值的項目
h = {foo: 0, bar: 1, baz: 2} h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.select # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select> e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
static VALUE rb_hash_select(VALUE hash) { VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); result = hash_dup_with_compare_by_id(hash); if (!RHASH_EMPTY_P(hash)) { rb_hash_foreach(result, keep_if_i, result); compact_after_delete(result); } return result; }
傳回 self
,其項目是區塊傳回真值的項目
h = {foo: 0, bar: 1, baz: 2} h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1}
如果未移除任何項目,則傳回 nil
。
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.select! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select!> e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
static VALUE rb_hash_select_bang(VALUE hash) { st_index_t n; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); n = RHASH_SIZE(hash); if (!n) return Qnil; rb_hash_foreach(hash, keep_if_i, hash); if (n == RHASH_SIZE(hash)) return Qnil; return hash; }
移除第一個雜湊項目(請參閱 項目順序);傳回一個包含已移除鍵和值的 2 元素 陣列
h = {foo: 0, bar: 1, baz: 2} h.shift # => [:foo, 0] h # => {:bar=>1, :baz=>2}
如果雜湊表是空的,則傳回 nil。
static VALUE rb_hash_shift(VALUE hash) { struct shift_var var; rb_hash_modify_check(hash); if (RHASH_AR_TABLE_P(hash)) { var.key = Qundef; if (!hash_iterating_p(hash)) { if (ar_shift(hash, &var.key, &var.val)) { return rb_assoc_new(var.key, var.val); } } else { rb_hash_foreach(hash, shift_i_safe, (VALUE)&var); if (!UNDEF_P(var.key)) { rb_hash_delete_entry(hash, var.key); return rb_assoc_new(var.key, var.val); } } } if (RHASH_ST_TABLE_P(hash)) { var.key = Qundef; if (!hash_iterating_p(hash)) { if (st_shift(RHASH_ST_TABLE(hash), &var.key, &var.val)) { return rb_assoc_new(var.key, var.val); } } else { rb_hash_foreach(hash, shift_i_safe, (VALUE)&var); if (!UNDEF_P(var.key)) { rb_hash_delete_entry(hash, var.key); return rb_assoc_new(var.key, var.val); } } } return Qnil; }
傳回 self
中的項目數目
{foo: 0, bar: 1, baz: 2}.length # => 3
VALUE rb_hash_size(VALUE hash) { return INT2FIX(RHASH_SIZE(hash)); }
傳回一個新的雜湊物件,其中包含指定 keys
的項目
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; }
將給定的 值
與給定的 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}
對於 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; }
傳回 self
。
static VALUE rb_hash_to_hash(VALUE hash) { return hash; }
傳回一個 Proc
物件,將金鑰對應至其值
h = {foo: 0, bar: 1, baz: 2} proc = h.to_proc proc.class # => Proc proc.call(:foo) # => 0 proc.call(:bar) # => 1 proc.call(:nosuch) # => nil
static VALUE rb_hash_to_proc(VALUE hash) { return rb_func_lambda_new(hash_proc_call, hash, 1, 1); }
傳回一個新的 Hash 物件;每個項目都有
-
區塊提供的金鑰。
-
self
的值。
可以提供一個選用的 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; }
與 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; }
傳回一個新的 Hash 物件;每個項目都有
-
self
的金鑰。 -
區塊提供的值。
轉換值
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_values {|value| value * 100} h1 # => {:foo=>0, :bar=>100, :baz=>200}
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.transform_values # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values> h1 = e.each { |value| value * 100} h1 # => {:foo=>0, :bar=>100, :baz=>200}
static VALUE rb_hash_transform_values(VALUE hash) { VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); result = hash_dup_with_compare_by_id(hash); SET_DEFAULT(result, Qnil); if (!RHASH_EMPTY_P(hash)) { rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result); compact_after_delete(result); } return result; }
傳回 self
,其鍵值不變,且其值由指定的區塊決定。
h = {foo: 0, bar: 1, baz: 2} h.transform_values! {|value| value * 100} # => {:foo=>0, :bar=>100, :baz=>200}
如果未提供區塊,則傳回新的 Enumerator
h = {foo: 0, bar: 1, baz: 2} e = h.transform_values! # => #<Enumerator: {:foo=>0, :bar=>100, :baz=>200}:transform_values!> h1 = e.each {|value| value * 100} h1 # => {:foo=>0, :bar=>100, :baz=>200}
static VALUE rb_hash_transform_values_bang(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash); } return hash; }
傳回一個新的 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; }
傳回一個新的 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; }