class Hash
Hash 对象将每个唯一的键映射到一个特定的值。
哈希在某些方面与 Array 相似,但
-
数组索引始终是整数。
-
哈希键几乎可以是任何对象。
Hash 数据语法
哈希条目的原始语法使用“哈希火箭” =>
h = {:foo => 0, :bar => 1, :baz => 2} h # => {foo: 0, bar: 1, baz: 2}
或者,但仅适用于符号键,您可以使用较新的 JSON 风格语法,其中每个裸词都变成一个符号
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}
您还可以混合使用样式
h = {foo: 0, :bar => 1, 'baz': 2} h # => {foo: 0, bar: 1, baz: 2}
但是,对于非裸词或字符串键尝试 JSON 风格语法会导致错误
# Raises SyntaxError (syntax error, unexpected ':', expecting =>):
h = {0: 'zero'}
值可以省略,这意味着将通过键的名称从上下文中获取该值
x = 0 y = 100 h = {x:, y:} h # => {x: 0, y: 100}
常见用法
您可以使用哈希为对象命名
person = {name: 'Matz', language: 'Ruby'} person # => {name: "Matz", language: "Ruby"}
您可以使用哈希为方法参数命名
def some_method(hash) p hash end some_method({foo: 0, bar: 1, baz: 2}) # => {foo: 0, bar: 1, baz: 2}
注意:当方法调用中的最后一个参数是哈希时,可以省略花括号
some_method(foo: 0, bar: 1, baz: 2) # => {foo: 0, bar: 1, baz: 2}
您可以使用哈希初始化对象
class Dev attr_accessor :name, :language def initialize(hash) self.name = hash[:name] self.language = hash[:language] end end matz = Dev.new(name: 'Matz', language: 'Ruby') matz # => #<Dev: @name="Matz", @language="Ruby">
创建 Hash
您可以使用以下方式显式创建 Hash 对象:
-
一个 哈希字面量。
您可以使用以下方法将某些对象转换为哈希:
-
方法
Kernel#Hash。
您可以通过调用方法 Hash.new 来创建一个哈希
# Create an empty hash. h = Hash.new h # => {} h.class # => Hash
您可以通过调用方法 Hash.[] 来创建一个哈希
# Create an empty hash. h = Hash[] h # => {} # Create a hash with initial entries. h = Hash[foo: 0, bar: 1, baz: 2] h # => {foo: 0, bar: 1, baz: 2}
您可以使用其字面量形式(花括号)创建哈希
# Create an empty hash. h = {} h # => {} # Create a +Hash+ with initial entries. h = {foo: 0, bar: 1, baz: 2} h # => {foo: 0, bar: 1, baz: 2}
Hash 值基础
检索哈希值(实例方法 [])的最简单方法
h = {foo: 0, bar: 1, baz: 2} h[:foo] # => 0
创建或更新哈希值(实例方法 []=)的最简单方法
h = {foo: 0, bar: 1, baz: 2} h[:bat] = 3 # => 3 h # => {foo: 0, bar: 1, baz: 2, bat: 3} h[:foo] = 4 # => 4 h # => {foo: 4, bar: 1, baz: 2, bat: 3}
删除哈希条目(实例方法 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返回的字符串。
新哈希根据给定条目具有初始顺序
h = Hash[foo: 0, bar: 1] h # => {foo: 0, bar: 1}
新条目添加到末尾
h[:baz] = 2 h # => {foo: 0, bar: 1, baz: 2}
更新值不会影响顺序
h[:baz] = 3 h # => {foo: 0, bar: 1, baz: 3}
但重新创建已删除的条目会影响顺序
h.delete(:foo) h[:foo] = 5 h # => {bar: 1, baz: 3, foo: 5}
Hash 键
Hash 键等价性
当两个对象的 hash 值相同且两个对象彼此 eql? 时,它们被视为相同的哈希键。
修改活动Hash 键
在活动 Hash 中修改键会损坏哈希的索引。
此 Hash 的键是数组
a0 = [ :foo, :bar ] a1 = [ :baz, :bat ] h = {a0 => 0, a1 => 1} h.include?(a0) # => true h[a0] # => 0 a0.hash # => 110002110
修改数组元素 a0[0] 会更改其哈希值
a0[0] = :bam a0.hash # => 1069447059
并损坏 Hash 索引
h.include?(a0) # => false h[a0] # => nil
您可以使用 rehash 方法修复哈希索引
h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1} h.include?(a0) # => true h[a0] # => 0
字符串键始终是安全的。这是因为作为键传递的未冻结字符串将被复制和冻结的字符串替换
s = 'foo' s.frozen? # => false h = {s => 0} first_key = h.keys.first first_key.frozen? # => true
用户定义的Hash 键
要用作 Hash 键,对象必须实现 hash 和 eql? 方法。注意:如果 Hash 使用 compare_by_identity,则此要求不适用,因为比较将依赖于键的对象 ID 而不是 hash 和 eql?。
Object 为 hash 和 eq? 定义了基本实现,使每个对象成为一个不同的键。通常,用户定义的类会覆盖这些方法以提供有意义的行为,或者继承 Struct,它具有这些方法的有用定义。
hash 的典型实现基于对象的 data,而 eql? 通常别名为重写的 == 方法
class Book attr_reader :author, :title def initialize(author, title) @author = author @title = title end def ==(other) self.class === other && other.author == @author && other.title == @title end alias eql? == def hash [self.class, @author, @title].hash end end book1 = Book.new 'matz', 'Ruby in a Nutshell' book2 = Book.new 'matz', 'Ruby in a Nutshell' reviews = {} reviews[book1] = 'Great reference!' reviews[book2] = 'Nice and compact!' reviews.length #=> 1
键未找到?
当一个方法尝试检索并返回一个键的值,并且该键被找到时,返回的值是与该键关联的值。
但是,如果键未找到怎么办?在这种情况下,某些方法将返回默认值,而其他方法将引发 KeyError。
Nil 返回值
如果您希望在找不到键时返回 nil,您可以调用
-
[](key)(通常写为#[key]。
您可以覆盖 []、dig 和 values_at(但不能覆盖 assoc)的这些行为;请参阅 Hash 默认值。
KeyError
如果您希望在找不到键时引发 KeyError,您可以调用
Hash 默认值
对于某些方法([]、dig 和 values_at),找不到键的返回值由两个哈希属性决定:
-
默认值:由方法
default返回。 -
默认 proc:由方法
default_proc返回。
在简单情况下,两者都为 nil,并且这些方法在找不到键时返回 nil;请参阅上面的 Nil 返回值。
请注意,本节(“Hash 默认值”)
任何键的默认值
您可以为哈希定义一个任何键的默认值,即一个将为任何未找到的键返回的值
-
default_proc的值必须为nil。 -
default的值(可以是任何对象,包括nil)将为未找到的键返回。
您可以在创建哈希时使用 Hash.new 和选项 default_value 来设置默认值,或者稍后使用方法 default=。
注意:虽然 default 的值可以是任何对象,但使用可变对象可能不是个好主意。
每个键的默认值
您可以为哈希定义一个每个键的默认值,即一个 Proc,它将根据键本身返回一个值。
您可以在创建哈希时使用 Hash.new 和块来设置默认 proc,或者稍后使用方法 default_proc=。
请注意,proc 可以修改 self,但以这种方式修改 self 不是线程安全的;多个线程可以并发地为同一个键调用默认 proc。
方法默认值
对于两个方法,您可以为找不到的键指定一个默认值,该默认值仅在单次方法调用中生效(而不是在后续调用中生效)
-
对于方法
fetch,您可以指定一个任何键的默认值 -
对于方法
fetch或方法fetch_values,您可以通过块指定一个每个键的默认值。
这里有什么
首先,其他地方。类 Hash
-
继承自 Object 类。
-
包含 Enumerable 模块,该模块提供了数十种额外的方法。
此处,类 Hash 提供了有用的方法,用于
类 Hash 还包括来自模块 Enumerable 的方法。
创建 Hash 的方法
-
::[]:返回一个填充了给定对象的新的哈希。 -
::new:返回一个新的空哈希。 -
::try_convert:返回一个由给定对象创建的新哈希。
设置 Hash 状态的方法
-
compare_by_identity:将self设置为仅考虑身份来比较键。 -
default=:将默认值设置为给定值。 -
default_proc=:将默认 proc 设置为给定的 proc。 -
rehash:通过重新计算每个键的哈希索引来重建哈希表。
查询方法
-
any?:返回是否有任何元素满足给定条件。 -
compare_by_identity?:返回哈希在比较键时是否仅考虑身份。 -
default:返回默认值,或给定键的默认值。 -
default_proc:返回默认 proc。 -
empty?:返回是否有条目。 -
eql?:返回给定对象是否等于self。 -
hash:返回整数哈希码。 -
has_value?(别名为value?):返回给定对象是否是self中的值。
比较方法
-
<:返回self是否是给定对象的真子集。 -
<=:返回self是否是给定对象的子集。 -
==:返回给定对象是否等于self。 -
>:返回self是否是给定对象的真超集 -
>=:返回self是否是给定对象的超集。
获取元素的方法
-
[]:返回与给定键关联的值。 -
assoc:返回一个包含给定键及其值的 2 元素数组。 -
dig:返回嵌套对象中由给定键和其他参数指定的对象。 -
fetch:返回给定键的值。 -
fetch_values:返回包含与给定键关联的值的数组。 -
key:返回具有给定值的第一个找到条目的键。 -
keys:返回一个包含self中所有键的数组。 -
rassoc:返回一个由具有给定值的第一个找到条目的键和值组成的 2 元素数组。 -
values:返回一个包含self中所有值的数组。 -
values_at:返回一个包含给定键的值的数组。
赋值方法
-
merge:返回通过将每个给定哈希合并到self的副本中而形成的哈希。 -
replace(别名为initialize_copy):将self的整个内容替换为给定哈希的内容。
删除方法
这些方法从 self 中移除条目
-
clear:从self中移除所有条目。 -
compact!:从self中移除所有nil值条目。 -
delete:移除给定键的条目。 -
delete_if:移除由给定块选择的条目。 -
keep_if:仅保留由给定块选择的条目。 -
reject!:移除由给定块选择的条目。 -
shift:移除并返回第一个条目。
这些方法返回 self 的副本,其中包含一些已移除的条目
-
compact:返回self的副本,其中已移除所有nil值条目。 -
except:返回self的副本,其中已移除指定键的条目。 -
reject:返回self的副本,其中已移除由给定块指定的条目。 -
slice:返回一个包含给定键条目的哈希。
迭代方法
-
each_key:使用每个键调用给定的块。 -
each_value:使用每个值调用给定的块。
转换方法
-
flatten:返回一个self的一维展平数组。 -
to_a:返回一个包含 2 元素数组的新数组;每个嵌套数组包含来自self的键值对。 -
to_hash:返回self。 -
to_proc:返回一个将给定键映射到其值的 proc。
转换键和值的方法
-
invert:返回一个键值对都反转的新哈希。 -
transform_keys:返回self的副本,其中修改了键。 -
transform_keys!:修改self中的键 -
transform_values:返回self的副本,其中修改了值。 -
transform_values!:修改self中的值。
Public Class Methods
Source
static VALUE
rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
{
VALUE hash, tmp;
if (argc == 1) {
tmp = rb_hash_s_try_convert(Qnil, argv[0]);
if (!NIL_P(tmp)) {
if (!RHASH_EMPTY_P(tmp) && rb_hash_compare_by_id_p(tmp)) {
/* hash_copy for non-empty hash will copy compare_by_identity
flag, but we don't want it copied. Work around by
converting hash to flattened array and using that. */
tmp = rb_hash_to_a(tmp);
}
else {
hash = hash_alloc(klass);
if (!RHASH_EMPTY_P(tmp))
hash_copy(hash, tmp);
return hash;
}
}
else {
tmp = rb_check_array_type(argv[0]);
}
if (!NIL_P(tmp)) {
long i;
hash = hash_alloc(klass);
for (i = 0; i < RARRAY_LEN(tmp); ++i) {
VALUE e = RARRAY_AREF(tmp, i);
VALUE v = rb_check_array_type(e);
VALUE key, val = Qnil;
if (NIL_P(v)) {
rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)",
rb_builtin_class_name(e), i);
}
switch (RARRAY_LEN(v)) {
default:
rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)",
RARRAY_LEN(v));
case 2:
val = RARRAY_AREF(v, 1);
case 1:
key = RARRAY_AREF(v, 0);
rb_hash_aset(hash, key, val);
}
}
return hash;
}
}
if (argc % 2 != 0) {
rb_raise(rb_eArgError, "odd number of arguments for Hash");
}
hash = hash_alloc(klass);
rb_hash_bulk_insert(argc, argv, hash);
hash_verify(hash);
return hash;
}
返回一个由给定对象(如果存在)填充的新 Hash 对象。请参阅 Hash::new。
如果没有给出参数,则返回一个新的空哈希。
给出一个参数 other_hash,它是一个哈希,返回一个用该哈希中的条目初始化的新哈希(但不是用它的 default 或 default_proc)
h = {foo: 0, bar: 1, baz: 2} Hash[h] # => {foo: 0, bar: 1, baz: 2}
给出一个参数 2_element_arrays,它是一个 2 元素数组的数组,返回一个新哈希,其中每个给定的 2 元素数组形成一个键值对条目
Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {foo: 0, bar: 1}
给定偶数个参数 objects,返回一个新哈希,其中每个连续的参数对是一个键值对条目
Hash[:foo, 0, :bar, 1] # => {foo: 0, bar: 1}
如果参数列表不符合上述任何一种,则引发 ArgumentError。
另请参阅 创建 Hash 的方法。
Source
# File hash.rb, line 37 def initialize(ifnone = (ifnone_unset = true), capacity: 0, &block) Primitive.rb_hash_init(capacity, ifnone_unset, ifnone, block) end
返回一个新的空 Hash 对象。
初始化 Hash#default 和 Hash#default_proc 的值,它们决定了找不到给定键时的行为;请参阅 键未找到?。
默认情况下,哈希对于 default 和 default_proc 都有 nil 值
h = Hash.new # => {} h.default # => nil h.default_proc # => nil
给定参数 default_value,设置哈希的 default 值
h = Hash.new(false) # => {} h.default # => false h.default_proc # => nil
给定块,设置 default_proc 值
h = Hash.new {|hash, key| "Hash #{hash}: Default value for #{key}" } h.default # => nil h.default_proc # => #<Proc:0x00000289b6fa7048 (irb):185> h[:nosuch] # => "Hash {}: Default value for nosuch"
如果同时给出了 default_value 和块,则引发 ArgumentError。
如果给出了可选关键字参数 capacity,其值为正整数 n,则用足够的容量初始化哈希以容纳 n 个条目而无需调整大小。
另请参阅 创建 Hash 的方法。
Source
static VALUE
rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
VALUE tmp = rb_hash_dup(hash);
if (RHASH_EMPTY_P(hash) && rb_hash_compare_by_id_p(hash)) {
rb_hash_compare_by_id(tmp);
}
RHASH(tmp)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
return tmp;
}
复制给定的哈希并添加 ruby2_keywords 标志。此方法不适用于日常使用;用于调试、研究和一些真正必需的情况,例如参数的重序列化。
h = {k: 1} h = Hash.ruby2_keywords_hash(h) def foo(k: 42) k end foo(*[h]) #=> 1 with neither a warning or an error
Source
static VALUE
rb_hash_s_ruby2_keywords_hash_p(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
return RBOOL(RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS);
}
检查给定的哈希是否被 Module#ruby2_keywords(或 Proc#ruby2_keywords)标记。此方法不适用于日常使用;用于调试、研究和一些真正必需的情况,例如参数的序列化。
ruby2_keywords def foo(*args) Hash.ruby2_keywords_hash?(args.last) end foo(k: 1) #=> true foo({k: 1}) #=> false
Source
static VALUE
rb_hash_s_try_convert(VALUE dummy, VALUE hash)
{
return rb_check_hash_type(hash);
}
如果 object 是一个哈希,则返回 object。
否则,如果 object 响应 :to_hash,则调用 object.to_hash;如果结果是哈希,则返回该结果,否则引发 TypeError。
否则,如果 object 不响应 :to_hash,则返回 nil。
Public Instance Methods
Source
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);
}
返回 self 的条目是否是 other 条目的真子集
h = {foo: 0, bar: 1} h < {foo: 0, bar: 1, baz: 2} # => true # Proper subset. h < {baz: 2, bar: 1, foo: 0} # => true # Order may differ. h < h # => false # Not a proper subset. h < {bar: 1, foo: 0} # => false # Not a proper subset. h < {foo: 0, bar: 1, baz: 2} # => false # Different key. h < {foo: 0, bar: 1, baz: 2} # => false # Different value.
另请参阅 Hash Inclusion。
如果 other_hash 不是哈希且无法转换为哈希,则引发 TypeError。
相关:另请参阅 比较方法。
Source
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);
}
返回 self 的条目是否是 other 的子集
h0 = {foo: 0, bar: 1} h1 = {foo: 0, bar: 1, baz: 2} h0 <= h0 # => true h0 <= h1 # => true h1 <= h0 # => false
另请参阅 Hash Inclusion。
如果 other_hash 不是哈希且无法转换为哈希,则引发 TypeError。
相关:另请参阅 比较方法。
Source
static VALUE
rb_hash_equal(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, FALSE);
}
返回 self 和 object 是否相等。
如果以下所有条件都为真,则返回 true:
-
object是一个Hash对象(或可以转换为一个)。 -
self和object具有相同的键(无论顺序如何)。 -
对于每个键
key,self[key] == object[key]。
否则,返回 false。
示例
h = {foo: 0, bar: 1} h == {foo: 0, bar: 1} # => true # Equal entries (same order) h == {bar: 1, foo: 0} # => true # Equal entries (different order). h == 1 # => false # Object not a hash. h == {} # => false # Different number of entries. h == {foo: 0, bar: 1} # => false # Different key. h == {foo: 0, bar: 1} # => false # Different value.
相关:另请参阅 比较方法。
Source
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);
}
如果 self 的条目是 other_hash 的真超集,则返回 true,否则返回 false。
h = {foo: 0, bar: 1, baz: 2} h > {foo: 0, bar: 1} # => true # Proper superset. h > {bar: 1, foo: 0} # => true # Order may differ. h > h # => false # Not a proper superset. h > {baz: 2, bar: 1, foo: 0} # => false # Not a proper superset. h > {foo: 0, bar: 1} # => false # Different key. h > {foo: 0, bar: 1} # => false # Different value.
另请参阅 Hash Inclusion。
如果 other_hash 不是哈希且无法转换为哈希,则引发 TypeError。
相关:另请参阅 比较方法。
Source
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);
}
如果 self 的条目是 other_hash 的超集,则返回 true,否则返回 false。
h0 = {foo: 0, bar: 1, baz: 2} h1 = {foo: 0, bar: 1} h0 >= h1 # => true h0 >= h0 # => true h1 >= h0 # => false
另请参阅 Hash Inclusion。
如果 other_hash 不是哈希且无法转换为哈希,则引发 TypeError。
相关:另请参阅 比较方法。
Source
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);
}
}
Source
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
bool iter_p = hash_iterating_p(hash);
rb_hash_modify(hash);
if (!RHASH_STRING_KEY_P(hash, key)) {
RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val);
}
else {
RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val);
}
return val;
}
将给定 object 与给定 key 关联;返回 object。
搜索等价于给定 key 的哈希键;请参阅 Hash 键等价性。
如果找到键,则将其值替换为给定的 object;顺序不受影响(请参阅 条目顺序)
h = {foo: 0, bar: 1} h[:foo] = 2 # => 2 h[:foo] # => 2
如果未找到 key,则创建给定 key 和 object 的新条目;新条目位于顺序的末尾(请参阅 条目顺序)
h = {foo: 0, bar: 1} h[:baz] = 2 # => 2 h[:baz] # => 2 h # => {:foo=>0, :bar=>1, :baz=>2}
Source
static VALUE
rb_hash_any_p(int argc, VALUE *argv, VALUE hash)
{
VALUE args[2];
args[0] = Qfalse;
rb_check_arity(argc, 0, 1);
if (RHASH_EMPTY_P(hash)) return Qfalse;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
args[1] = argv[0];
rb_hash_foreach(hash, any_p_i_pattern, (VALUE)args);
}
else {
if (!rb_block_given_p()) {
/* yields pairs, never false */
return Qtrue;
}
if (rb_block_pair_yield_optimizable())
rb_hash_foreach(hash, any_p_i_fast, (VALUE)args);
else
rb_hash_foreach(hash, any_p_i, (VALUE)args);
}
return args[0];
}
如果任何元素满足给定条件,则返回 true;否则返回 false。
如果 self 没有元素,则返回 false 且不使用参数或块;否则,行为如下:
不带参数也不带块,如果 self 非空,则返回 true,否则返回 false。
带有参数 entry 且不带块,如果对于任何键 key self.assoc(key) == entry,则返回 true,否则返回 false
h = {foo: 0, bar: 1, baz: 2} h.assoc(:bar) # => [:bar, 1] h.any?([:bar, 1]) # => true h.any?([:bar, 0]) # => false
不带参数且带块,使用每个键值对调用块;如果块返回真值,则返回 true,否则返回 false
h = {foo: 0, bar: 1, baz: 2} h.any? {|key, value| value < 3 } # => true h.any? {|key, value| value > 3 } # => false
同时带有参数 entry 和块,会发出警告并忽略块。
相关:Enumerable#any?(此方法将重写);另请参阅 获取方法。
Source
static VALUE
rb_hash_assoc(VALUE hash, VALUE key)
{
VALUE args[2];
if (RHASH_EMPTY_P(hash)) return Qnil;
if (RHASH_ST_TABLE_P(hash) && !RHASH_IDENTHASH_P(hash)) {
VALUE value = Qundef;
st_table assoctable = *RHASH_ST_TABLE(hash);
assoctable.type = &(struct st_hash_type){
.compare = assoc_cmp,
.hash = assoctable.type->hash,
};
VALUE arg = (VALUE)&(struct assoc_arg){
.tbl = &assoctable,
.key = (st_data_t)key,
};
if (RB_OBJ_FROZEN(hash)) {
value = assoc_lookup(arg);
}
else {
hash_iter_lev_inc(hash);
value = rb_ensure(assoc_lookup, arg, hash_foreach_ensure, hash);
}
hash_verify(hash);
if (!UNDEF_P(value)) return rb_assoc_new(key, value);
}
args[0] = key;
args[1] = Qnil;
rb_hash_foreach(hash, assoc_i, (VALUE)args);
return args[1];
}
如果找到给定 key,则返回其条目,作为一个包含该键及其值的 2 元素数组
h = {foo: 0, bar: 1, baz: 2} h.assoc(:bar) # => [:bar, 1]
如果找不到键,则返回 nil。
相关:另请参阅 获取方法。
Source
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 中移除所有条目;返回已清空的 self。
相关:另请参阅 删除方法。
Source
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}
相关:另请参阅 删除方法。
Source
static VALUE
rb_hash_compact_bang(VALUE hash)
{
st_index_t n;
rb_hash_modify_check(hash);
n = RHASH_SIZE(hash);
if (n) {
rb_hash_foreach(hash, delete_if_nil, hash);
if (n != RHASH_SIZE(hash))
return hash;
}
return Qnil;
}
如果 self 包含任何 nil 值条目,则返回 self,其中已移除所有 nil 值条目;否则返回 nil
h = {foo: 0, bar: nil, baz: 2, bat: nil} h.compact! h # => {foo: 0, baz: 2} h.compact! # => nil
相关:另请参阅 删除方法。
Source
VALUE
rb_hash_compare_by_id(VALUE hash)
{
VALUE tmp;
st_table *identtable;
if (rb_hash_compare_by_id_p(hash)) return hash;
rb_hash_modify_check(hash);
if (hash_iterating_p(hash)) {
rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
}
if (RHASH_TABLE_EMPTY_P(hash)) {
// Fast path: There's nothing to rehash, so we don't need a `tmp` table.
// We're most likely an AR table, so this will need an allocation.
ar_force_convert_table(hash, __FILE__, __LINE__);
HASH_ASSERT(RHASH_ST_TABLE_P(hash));
RHASH_ST_TABLE(hash)->type = &identhash;
}
else {
// Slow path: Need to rehash the members of `self` into a new
// `tmp` table using the new `identhash` compare/hash functions.
tmp = hash_alloc(0);
hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
identtable = RHASH_ST_TABLE(tmp);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
rb_hash_free(hash);
// We know for sure `identtable` is an st table,
// so we can skip `ar_force_convert_table` here.
RHASH_ST_TABLE_SET(hash, identtable);
RHASH_ST_CLEAR(tmp);
}
return hash;
}
将 self 设置为使用身份(而不是仅仅相等性)来比较键;返回 self
默认情况下,两个键被视为相同的键当且仅当它们是相等的对象(根据方法 eql?)
h = {} h['x'] = 0 h['x'] = 1 # Overwrites. h # => {"x"=>1}
调用此方法后,两个键被视为相同的键当且仅当它们是同一个对象
h.compare_by_identity h['x'] = 2 # Does not overwrite. h # => {"x"=>1, "x"=>2}
相关:compare_by_identity?;另请参阅 比较方法。
Source
VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
return RBOOL(RHASH_IDENTHASH_P(hash));
}
返回是否调用了 compare_by_identity
h = {} h.compare_by_identity? # => false h.compare_by_identity h.compare_by_identity? # => true
相关:compare_by_identity;另请参阅 比较方法。
Source
static VALUE
rb_hash_default(int argc, VALUE *argv, VALUE hash)
{
VALUE ifnone;
rb_check_arity(argc, 0, 1);
ifnone = RHASH_IFNONE(hash);
if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
if (argc == 0) return Qnil;
return call_default_proc(ifnone, hash, argv[0]);
}
return ifnone;
}
返回给定 key 的默认值。返回值将由默认 proc 或默认值决定。请参阅 Hash 默认值。
不带参数,返回当前默认值
h = {} h.default # => nil
如果给出了 key,则返回 key 的默认值,无论该键是否存在
h = Hash.new { |hash, key| hash[key] = "No key #{key}"} h[:foo] = "Hello" h.default(:foo) # => "No key foo"
Source
VALUE
rb_hash_set_default(VALUE hash, VALUE ifnone)
{
rb_hash_modify_check(hash);
SET_DEFAULT(hash, ifnone);
return ifnone;
}
将默认值设置为 value;返回 value
h = {} h.default # => nil h.default = false # => false h.default # => false
请参阅 Hash 默认值。
Source
static VALUE
rb_hash_default_proc(VALUE hash)
{
if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
return RHASH_IFNONE(hash);
}
return Qnil;
}
返回 self 的默认 proc(请参阅 Hash 默认值)
h = {} h.default_proc # => nil h.default_proc = proc {|hash, key| "Default value for #{key}" } h.default_proc.class # => Proc
Source
VALUE
rb_hash_set_default_proc(VALUE hash, VALUE proc)
{
VALUE b;
rb_hash_modify_check(hash);
if (NIL_P(proc)) {
SET_DEFAULT(hash, proc);
return proc;
}
b = rb_check_convert_type_with_id(proc, T_DATA, "Proc", idTo_proc);
if (NIL_P(b) || !rb_obj_is_proc(b)) {
rb_raise(rb_eTypeError,
"wrong default_proc type %s (expected Proc)",
rb_obj_classname(proc));
}
proc = b;
SET_PROC_DEFAULT(hash, proc);
return proc;
}
将 self 的默认 proc 设置为 proc(请参阅 Hash 默认值)
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
Source
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 的条目,则删除该条目并返回其关联的值;否则返回 nil 或调用给定的块。
不带块且找到 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}
相关:另请参阅 删除方法。
Source
VALUE
rb_hash_delete_if(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_foreach(hash, delete_if_i, hash);
compact_after_delete(hash);
}
return hash;
}
带块,使用每个键值对调用块,删除块返回真值的每个条目,并返回 self
h = {foo: 0, bar: 1, baz: 2} h.delete_if {|key, value| value > 0 } # => {foo: 0}
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 删除方法。
Source
static VALUE
rb_hash_dig(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
self = rb_hash_aref(self, *argv);
if (!--argc) return self;
++argv;
return rb_obj_dig(argc, argv, self, Qnil);
}
查找并返回嵌套对象中的对象,如 key 和 identifiers 所指定。
嵌套对象可以是各种类的实例。请参阅 Dig 方法。
嵌套哈希
h = {foo: {bar: {baz: 2}}} h.dig(:foo) # => {bar: {baz: 2}} h.dig(:foo, :bar) # => {baz: 2} h.dig(:foo, :bar, :baz) # => 2 h.dig(:foo, :bar, :BAZ) # => nil
嵌套哈希和数组
h = {foo: {bar: [:a, :b, :c]}} h.dig(:foo, :bar, 2) # => :c
如果找不到这样的对象,则返回 哈希默认值
h = {foo: {bar: [:a, :b, :c]}} h.dig(:hello) # => nil h.default_proc = -> (hash, _key) { hash } h.dig(:hello, :world) # => {:foo=>{:bar=>[:a, :b, :c]}}
相关:获取方法。
Source
static VALUE
rb_hash_each_key(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_foreach(hash, each_key_i, 0);
return hash;
}
带块,使用每个键调用块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_key {|key| puts key } # => {foo: 0, bar: 1, baz: 2}
输出
foo bar baz
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 迭代方法。
Source
static VALUE
rb_hash_each_pair(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
if (rb_block_pair_yield_optimizable())
rb_hash_foreach(hash, each_pair_i_fast, 0);
else
rb_hash_foreach(hash, each_pair_i, 0);
return hash;
}
带块,使用每个键值对调用块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_pair {|key, value| puts "#{key}: #{value}"} # => {foo: 0, bar: 1, baz: 2}
输出
foo: 0 bar: 1 baz: 2
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 迭代方法。
Source
static VALUE
rb_hash_each_value(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_foreach(hash, each_value_i, 0);
return hash;
}
带块,使用每个值调用块;返回 self
h = {foo: 0, bar: 1, baz: 2} h.each_value {|value| puts value } # => {foo: 0, bar: 1, baz: 2}
输出
0 1 2
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 迭代方法。
Source
VALUE
rb_hash_empty_p(VALUE hash)
{
return RBOOL(RHASH_EMPTY_P(hash));
}
Source
static VALUE
rb_hash_eql(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, TRUE);
}
Source
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;
}
返回 self 的副本,其中不包含指定 keys 的条目;忽略任何未找到的 keys
h = {foo:0, bar: 1, baz: 2} # => {:foo=>0, :bar=>1, :baz=>2} h.except(:baz, :foo) # => {:bar=>1} h.except(:bar, :nosuch) # => {:foo=>0, :baz=>2}
相关:另请参阅 删除方法。
Source
static VALUE
rb_hash_fetch_m(int argc, VALUE *argv, VALUE hash)
{
VALUE key;
st_data_t val;
long block_given;
rb_check_arity(argc, 1, 2);
key = argv[0];
block_given = rb_block_given_p();
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
if (hash_stlike_lookup(hash, key, &val)) {
return (VALUE)val;
}
else {
if (block_given) {
return rb_yield(key);
}
else if (argc == 1) {
VALUE desc = rb_protect(rb_inspect, key, 0);
if (NIL_P(desc)) {
desc = rb_any_to_s(key);
}
desc = rb_str_ellipsize(desc, 65);
rb_key_err_raise(rb_sprintf("key not found: %"PRIsVALUE, desc), hash, key);
}
else {
return argv[1];
}
}
}
不带块,如果找到给定 key,则返回其值;
h = {foo: 0, bar: 1, baz: 2} h.fetch(:bar) # => 1
如果未找到键,则返回 default_value(如果给定),否则引发 KeyError。
h.fetch(:nosuch, :default) # => :default h.fetch(:nosuch) # Raises KeyError.
带块,使用 key 调用块并返回块的返回值
{}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch"
请注意,此方法不使用 default 或 default_proc 的值。
相关:另请参阅 获取方法。
Source
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;
}
Source
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;
}
给定正整数 depth,返回一个新数组,该数组是 self 到给定 depth 的递归展平。
在每个递归级别
-
每个值为数组的元素都被“展平”(即,替换为其单独的数组元素);请参阅
Array#flatten。 -
每个值不是数组的元素保持不变,即使该值是具有实例方法 flatten(如哈希)的对象。
示例;请注意,条目 foo: {bar: 1, baz: 2} 永远不会被展平。
h = {foo: {bar: 1, baz: 2}, bat: [:bam, [:bap, [:bah]]]} h.flatten(1) # => [:foo, {:bar=>1, :baz=>2}, :bat, [:bam, [:bap, [:bah]]]] h.flatten(2) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, [:bap, [:bah]]] h.flatten(3) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, [:bah]] h.flatten(4) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah] h.flatten(5) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
给定负整数 depth,展平所有级别
h.flatten(-1) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
给定 depth 为零,返回等同于 to_a
h.flatten(0) # => [[:foo, {:bar=>1, :baz=>2}], [:bat, [:bam, [:bap, [:bah]]]]]
相关:另请参阅 转换方法。
Source
static VALUE
rb_hash_has_value(VALUE hash, VALUE val)
{
VALUE data[2];
data[0] = Qfalse;
data[1] = val;
rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data);
return data[0];
}
返回 value 是否是 self 中的值。
相关:查询方法。
Source
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);
}
返回哈希的整数哈希码。
两个哈希具有相同的哈希码,如果它们的内容相同(无论顺序如何)
h1 = {foo: 0, bar: 1, baz: 2} h2 = {baz: 2, bar: 1, foo: 0} h2.hash == h1.hash # => true h2.eql? h1 # => true
相关:另请参阅 查询方法。
Source
VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
return RBOOL(hash_stlike_lookup(hash, key, NULL));
}
返回 key 是否是 self 中的键
h = {foo: 0, bar: 1, baz: 2} h.include?(:bar) # => true h.include?(:BAR) # => false
相关:查询方法。
Source
static VALUE
rb_hash_replace(VALUE hash, VALUE hash2)
{
rb_hash_modify_check(hash);
if (hash == hash2) return hash;
if (hash_iterating_p(hash)) {
rb_raise(rb_eRuntimeError, "can't replace hash during iteration");
}
hash2 = to_hash(hash2);
COPY_DEFAULT(hash, hash2);
if (RHASH_AR_TABLE_P(hash)) {
hash_ar_free_and_clear_table(hash);
}
else {
hash_st_free_and_clear_table(hash);
}
hash_copy(hash, hash2);
return hash;
}
Source
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);
}
返回一个包含哈希条目的新字符串
h = {foo: 0, bar: 1, baz: 2} h.inspect # => "{foo: 0, bar: 1, baz: 2}"
相关:另请参阅 转换方法。
Source
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;
}
Source
static VALUE
rb_hash_keep_if(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_foreach(hash, keep_if_i, hash);
}
return hash;
}
带块,为每个键值对调用块;如果块返回真值,则保留该条目;否则删除该条目;返回 self
h = {foo: 0, bar: 1, baz: 2} h.keep_if { |key, value| key.start_with?('b') } # => {bar: 1, baz: 2}
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 删除方法。
Source
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];
}
Source
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;
}
Source
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 中的每个参数 other_hash 必须是一个哈希。
给定参数 other_hashes 且不带块,返回通过将每个连续的 other_hash 合并到 self 的副本中而形成的新哈希;返回该副本;对于 other_hash 中的每个连续条目
-
对于新键,条目被添加到
self的末尾。 -
对于重复的键,该条目会覆盖
self中的条目,其位置保持不变。
示例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h.merge(h1, h2) # => {foo: 0, bar: 4, baz: 2, bat: 6, bam: 5}
当提供 other_hashes 参数和块时,其行为如上所述,但对于重复的键,覆盖条目的值不是来自 other_hash 中的条目,而是来自块。
-
块会以重复的键以及
self和other_hash中的值为参数被调用。 -
块的返回值将成为
self中条目的新值。
示例
h = {foo: 0, bar: 1, baz: 2} h1 = {bat: 3, bar: 4} h2 = {bam: 5, bat:6} h.merge(h1, h2) { |key, old_value, new_value| old_value + new_value } # => {foo: 0, bar: 5, baz: 2, bat: 9, bam: 5}
不带参数时,返回 self 的副本;如果提供了块,则忽略该块。
相关:请参阅 赋值方法。
Source
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];
}
Source
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 的哈希表;返回 self。调用此方法可确保哈希表有效。
如果在条目创建后更改了键的哈希值,则哈希表将失效。请参阅 修改活动哈希键。
Source
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 的副本,其中删除了零个或多个条目;使用每个键值对调用块;如果块返回真值,则在副本中排除该条目,否则包含该条目。
h = {foo: 0, bar: 1, baz: 2} h.reject {|key, value| key.start_with?('b') } # => {foo: 0}
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 删除方法。
Source
static VALUE
rb_hash_reject_bang(VALUE hash)
{
st_index_t n;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify(hash);
n = RHASH_SIZE(hash);
if (!n) return Qnil;
rb_hash_foreach(hash, delete_if_i, hash);
if (n == RHASH_SIZE(hash)) return Qnil;
return hash;
}
当提供块时,使用每个条目的键和值调用块;如果块返回真值,则从 self 中删除该条目。
如果删除了任何条目,则返回 self,否则返回 nil。
h = {foo: 0, bar: 1, baz: 2} h.reject! {|key, value| value < 2 } # => {baz: 2} h.reject! {|key, value| value < 2 } # => nil
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 删除方法。
将 self 的全部内容替换为 other_hash 的内容;返回 self。
h = {foo: 0, bar: 1, baz: 2} h.replace({bat: 3, bam: 4}) # => {bat: 3, bam: 4}
还会将 self 的默认值或过程替换为 other_hash 的默认值或过程。
h = {} other = Hash.new(:ok) h.replace(other) h.default # => :ok
相关:请参阅 赋值方法。
Source
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;
}
当提供块时,使用每个条目的键和值调用块;返回一个新哈希,其条目是块返回真值的所有条目。
h = {foo: 0, bar: 1, baz: 2} h.select {|key, value| value < 2 } # => {foo: 0, bar: 1}
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 删除方法。
Source
static VALUE
rb_hash_select_bang(VALUE hash)
{
st_index_t n;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
n = RHASH_SIZE(hash);
if (!n) return Qnil;
rb_hash_foreach(hash, keep_if_i, hash);
if (n == RHASH_SIZE(hash)) return Qnil;
return hash;
}
当提供块时,使用每个条目的键和值调用块;从 self 中删除块返回 false 或 nil 的每个条目。
如果删除了任何条目,则返回 self,否则返回 nil。
h = {foo: 0, bar: 1, baz: 2} h.select! {|key, value| value < 2 } # => {foo: 0, bar: 1} h.select! {|key, value| value < 2 } # => nil
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 删除方法。
Source
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;
}
Source
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;
}
返回一个新哈希,其中包含 self 中给定 keys 的条目;忽略任何未找到的键。
h = {foo: 0, bar: 1, baz: 2} h.slice(:baz, :foo, :nosuch) # => {baz: 2, foo: 0}
相关:另请参阅 删除方法。
Source
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;
}
将 self 的所有元素作为 2 元素数组的数组返回;每个嵌套数组包含 self 的一个键值对。
h = {foo: 0, bar: 1, baz: 2} h.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
相关:另请参阅 转换方法。
Source
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;
}
Source
static VALUE
rb_hash_to_proc(VALUE hash)
{
return rb_func_lambda_new(hash_proc_call, hash, 1, 1);
}
Source
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;
}
当提供参数、块或两者兼有时,根据 self、参数和/或块派生一个新哈希 new_hash;其键可能全部、部分或都不与 self 中的键相同。
当提供块且不带参数时,new_hash 的键仅由块确定。
对于 self 中的每个键/值对 old_key/value,使用 old_key 调用块;块的返回值成为 new_key;设置 new_hash[new_key] = value;重复的键会覆盖。
h = {foo: 0, bar: 1, baz: 2} h.transform_keys {|old_key| old_key.to_s } # => {"foo" => 0, "bar" => 1, "baz" => 2} h.transform_keys {|old_key| 'xxx' } # => {"xxx" => 2}
当提供 other_hash 参数且不带块时,new_hash 可能包含 other_hash 提供的新键以及 self 提供的未更改的键。
对于 self 中的每个键/值对 old_key/old_value,在 other_hash 中查找键 old_key。
-
如果找到
old_key,则将其值other_hash[old_key]作为new_key;设置new_hash[new_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys(baz: :BAZ, bar: :BAR, foo: :FOO) # => {FOO: 0, BAR: 1, BAZ: 2} h.transform_keys(baz: :FOO, bar: :FOO, foo: :FOO) # => {FOO: 2}
-
如果未找到
old_key,则设置new_hash[old_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys({}) # => {foo: 0, bar: 1, baz: 2} h.transform_keys(baz: :foo) # => {foo: 2, bar: 1}
other_hash 中未使用的键将被忽略。
h = {foo: 0, bar: 1, baz: 2} h.transform_keys(bat: 3) # => {foo: 0, bar: 1, baz: 2}
当同时提供 other_hash 参数和块时,new_hash 包含由 other_hash 或块指定的新键,以及 self 提供的未更改的键。
对于 self 中的每个对 old_key 和 value
-
如果
other_hash包含键old_key(值为new_key),则不对该键调用块;设置new_hash[new_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys(baz: :BAZ, bar: :BAR, foo: :FOO) {|key| fail 'Not called' } # => {FOO: 0, BAR: 1, BAZ: 2}
-
如果
other_hash不包含键old_key,则使用old_key调用块,并将其返回值作为new_key;设置new_hash[new_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys(baz: :BAZ) {|key| key.to_s.reverse } # => {"oof" => 0, "rab" => 1, BAZ: 2} h.transform_keys(baz: :BAZ) {|key| 'ook' } # => {"ook" => 1, BAZ: 2}
不带参数也不带块时,返回一个新的 Enumerator。
相关:另请参阅 转换键和值的方法。
Source
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;
}
当提供参数、块或两者兼有时,从参数、块和 self 派生键;self 中的键可能全部、部分或都不更改。
当提供块且不带参数时,仅从块派生键;self 中的键可能全部、部分或都不更改。
对于 self 中的每个键/值对 old_key/value,使用 old_key 调用块;块的返回值成为 new_key;删除 old_key 的条目:self.delete(old_key);设置 self[new_key] = value;重复的键会覆盖。
h = {foo: 0, bar: 1, baz: 2} h.transform_keys! {|old_key| old_key.to_s } # => {"foo" => 0, "bar" => 1, "baz" => 2} h = {foo: 0, bar: 1, baz: 2} h.transform_keys! {|old_key| 'xxx' } # => {"xxx" => 2}
当提供 other_hash 参数且不带块时,从 other_hash 和 self 派生 self 的键;self 中的键可能全部、部分或都不更改。
对于 self 中的每个键/值对 old_key/old_value,在 other_hash 中查找键 old_key。
-
如果找到
old_key,则将other_hash[old_key]的值作为new_key;删除old_key的条目:self.delete(old_key);设置self[new_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys!(baz: :BAZ, bar: :BAR, foo: :FOO) # => {FOO: 0, BAR: 1, BAZ: 2} h = {foo: 0, bar: 1, baz: 2} h.transform_keys!(baz: :FOO, bar: :FOO, foo: :FOO) # => {FOO: 2}
-
如果未找到
old_key,则不执行任何操作。h = {foo: 0, bar: 1, baz: 2} h.transform_keys!({}) # => {foo: 0, bar: 1, baz: 2} h.transform_keys!(baz: :foo) # => {foo: 2, bar: 1}
other_hash 中未使用的键将被忽略。
h = {foo: 0, bar: 1, baz: 2} h.transform_keys!(bat: 3) # => {foo: 0, bar: 1, baz: 2}
当同时提供 other_hash 参数和块时,从 other_hash、块和 self 派生键;self 中的键可能全部、部分或都不更改。
对于 self 中的每个对 old_key 和 value
-
如果
other_hash包含键old_key(值为new_key),则不对该键调用块;删除old_key的条目:self.delete(old_key);设置self[new_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys!(baz: :BAZ, bar: :BAR, foo: :FOO) {|key| fail 'Not called' } # => {FOO: 0, BAR: 1, BAZ: 2}
-
如果
other_hash不包含键old_key,则使用old_key调用块,并将其返回值作为new_key;删除old_key的条目:self.delete(old_key);设置self[new_key] = value;重复的键会覆盖。h = {foo: 0, bar: 1, baz: 2} h.transform_keys!(baz: :BAZ) {|key| key.to_s.reverse } # => {"oof" => 0, "rab" => 1, BAZ: 2} h = {foo: 0, bar: 1, baz: 2} h.transform_keys!(baz: :BAZ) {|key| 'ook' } # => {"ook" => 1, BAZ: 2}
不带参数也不带块时,返回一个新的 Enumerator。
相关:另请参阅 转换键和值的方法。
Source
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)) {
transform_values(result);
compact_after_delete(result);
}
return result;
}
当提供块时,返回一个新哈希 new_hash;对于 self 中的每个对 key/value,使用 value 调用块并捕获其返回值为 new_value;将条目 key/new_value 添加到 new_hash。
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_values {|value| value * 100} h1 # => {foo: 0, bar: 100, baz: 200}
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 转换键和值的方法。
Source
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)) {
transform_values(hash);
}
return hash;
}
当提供块时,根据块更改 self 的值;返回 self。
对于 self 中的每个条目 key/old_value,使用 old_value 调用块,将其返回值捕获为 new_value,并将 self[key] = new_value 设置为。
h = {foo: 0, bar: 1, baz: 2} h.transform_values! {|value| value * 100} # => {foo: 0, bar: 100, baz: 200}
在没有块的情况下,返回一个新的 Enumerator。
相关:另请参阅 转换键和值的方法。
Source
static VALUE
rb_hash_update(int argc, VALUE *argv, VALUE self)
{
struct update_call_args args = {
.hash = self,
.argv = argv,
.argc = argc,
.block_given = rb_block_given_p(),
.iterating = false,
};
VALUE arg = (VALUE)&args;
rb_hash_modify(self);
return rb_ensure(rb_hash_update_call, arg, rb_hash_update_ensure, arg);
}
更新值和/或向 self 添加条目;返回 self。
other_hashes 中的每个参数 other_hash 必须是一个哈希。
不带块时,对于每个连续的 other_hash 中的连续条目 key/new_value
-
如果
key在self中,则设置self[key] = new_value,其位置保持不变。h0 = {foo: 0, bar: 1, baz: 2} h1 = {bar: 3, foo: -1} h0.update(h1) # => {foo: -1, bar: 3, baz: 2}
-
如果
key不在self中,则在self的末尾添加该条目。h = {foo: 0, bar: 1, baz: 2} h.update({bam: 3, bah: 4}) # => {foo: 0, bar: 1, baz: 2, bam: 3, bah: 4}
当提供块时,对于每个连续的 other_hash 中的连续条目 key/new_value
-
如果
key在self中,则从self[key]获取old_value,使用key、old_value和new_value调用块,并设置self[key] = new_value,其位置保持不变。season = {AB: 75, H: 20, HR: 3, SO: 17, W: 11, HBP: 3} today = {AB: 3, H: 1, W: 1} yesterday = {AB: 4, H: 2, HR: 1} season.update(yesterday, today) {|key, old_value, new_value| old_value + new_value } # => {AB: 82, H: 23, HR: 4, SO: 17, W: 12, HBP: 3}
-
如果
key不在self中,则在self的末尾添加该条目。h = {foo: 0, bar: 1, baz: 2} h.update({bat: 3}) { fail 'Cannot happen' } # => {foo: 0, bar: 1, baz: 2, bat: 3}
相关:请参阅 赋值方法。
Source
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;
}
Source
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;
}