class Hash
A Hash
maps each of its unique keys to a specific value.
A Hash
has certain similarities to an Array
, but:
Hash
Data Syntax¶ ↑
The older syntax for Hash
data uses the “hash rocket,” =>
:
h = {:foo => 0, :bar => 1, :baz => 2} h # => {foo: 0, bar: 1, baz: 2}
Alternatively, but only for a Hash
key that’s a Symbol
, you can use a newer JSON-style syntax, where each bareword becomes a Symbol:
h = {foo: 0, bar: 1, baz: 2} h # => {foo: 0, bar: 1, baz: 2}
You can also use a String
in place of a bareword:
h = {'foo': 0, 'bar': 1, 'baz': 2} h # => {foo: 0, bar: 1, baz: 2}
And you can mix the styles:
h = {foo: 0, :bar => 1, 'baz': 2} h # => {foo: 0, bar: 1, baz: 2}
But it’s an error to try the JSON-style syntax for a key that’s not a bareword or a String:
# Raises SyntaxError (syntax error, unexpected ':', expecting =>): h = {0: 'zero'}
Hash
value can be omitted, meaning that value will be fetched from the context by the name of the key:
x = 0 y = 100 h = {x:, y:} h # => {x: 0, y: 100}
Common Uses¶ ↑
You can use a Hash
to give names to objects:
person = {name: 'Matz', language: 'Ruby'} person # => {name: "Matz", language: "Ruby"}
You can use a Hash
to give names to method arguments:
def some_method(hash) p hash end some_method({foo: 0, bar: 1, baz: 2}) # => {foo: 0, bar: 1, baz: 2}
Note: when the last argument in a method call is a Hash
, the curly braces may be omitted:
some_method(foo: 0, bar: 1, baz: 2) # => {foo: 0, bar: 1, baz: 2}
You can use a Hash
to initialize an object:
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">
Creating a Hash
¶ ↑
You can create a Hash
object explicitly with:
-
A hash literal.
You can convert certain objects to Hashes with:
-
Method
Hash
.
You can create a Hash
by calling method Hash.new
.
Create an empty Hash
:
h = Hash.new h # => {} h.class # => Hash
You can create a Hash
by calling method 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}
You can create a Hash
by using its literal form (curly braces).
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
Value Basics¶ ↑
The simplest way to retrieve a Hash
value (instance method []
):
h = {foo: 0, bar: 1, baz: 2} h[:foo] # => 0
The simplest way to create or update a Hash
value (instance method []=
):
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}
The simplest way to delete a Hash
entry (instance method delete
):
h = {foo: 0, bar: 1, baz: 2} h.delete(:bar) # => 1 h # => {foo: 0, baz: 2}
Entry Order¶ ↑
A Hash
object presents its entries in the order of their creation. This is seen in:
-
Iterative methods such as
each
,each_key
,each_pair
,each_value
. -
Other order-sensitive methods such as
shift
,keys
,values
. -
The
String
returned by methodinspect
.
A new Hash
has its initial ordering per the given entries:
h = Hash[foo: 0, bar: 1] h # => {foo: 0, bar: 1}
New entries are added at the end:
h[:baz] = 2 h # => {foo: 0, bar: 1, baz: 2}
Updating a value does not affect the order:
h[:baz] = 3 h # => {foo: 0, bar: 1, baz: 3}
But re-creating a deleted entry can affect the order:
h.delete(:foo) h[:foo] = 5 h # => {bar: 1, baz: 3, foo: 5}
Hash
Keys¶ ↑
Hash
Key Equivalence¶ ↑
Two objects are treated as the same hash key when their hash
value is identical and the two objects are eql?
to each other.
Modifying an Active Hash
Key¶ ↑
Modifying a Hash
key while it is in use damages the hash’s index.
This Hash
has keys that are Arrays:
a0 = [ :foo, :bar ] a1 = [ :baz, :bat ] h = {a0 => 0, a1 => 1} h.include?(a0) # => true h[a0] # => 0 a0.hash # => 110002110
Modifying array element a0[0]
changes its hash value:
a0[0] = :bam a0.hash # => 1069447059
And damages the Hash
index:
h.include?(a0) # => false h[a0] # => nil
You can repair the hash index using method rehash
:
h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1} h.include?(a0) # => true h[a0] # => 0
A String
key is always safe. That’s because an unfrozen String
passed as a key will be replaced by a duplicated and frozen String:
s = 'foo' s.frozen? # => false h = {s => 0} first_key = h.keys.first first_key.frozen? # => true
User-Defined Hash
Keys¶ ↑
To be usable as a Hash
key, objects must implement the methods hash
and eql?
. Note: this requirement does not apply if the Hash
uses compare_by_identity
since comparison will then rely on the keys’ object id instead of hash
and eql?
.
Object
defines basic implementation for hash
and eq?
that makes each object a distinct key. Typically, user-defined classes will want to override these methods to provide meaningful behavior, or for example inherit Struct
that has useful definitions for these.
A typical implementation of hash
is based on the object’s data while eql?
is usually aliased to the overridden ==
method:
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
Key Not Found?¶ ↑
When a method tries to retrieve and return the value for a key and that key is found, the returned value is the value associated with the key.
But what if the key is not found? In that case, certain methods will return a default value while other will raise a KeyError.
Nil Return Value¶ ↑
If you want nil
returned for a not-found key, you can call:
-
[](key)
(usually written as#[key]
.
You can override these behaviors for []
, dig
, and values_at
(but not assoc
); see Hash Default.
KeyError¶ ↑
If you want KeyError
raised for a not-found key, you can call:
Hash Default¶ ↑
For certain methods ([]
, dig
, and values_at
), the return value for a not-found key is determined by two hash properties:
-
default value: returned by method
default
. -
default proc: returned by method
default_proc
.
In the simple case, both values are nil
, and the methods return nil
for a not-found key; see Nil Return Value above.
Note that this entire section (“Hash Default”):
-
Does not apply to methods
assoc
,fetch
, orfetch_values
, which are not affected by the default value or default proc.
Any-Key Default¶ ↑
You can define an any-key default for a hash; that is, a value that will be returned for any not-found key:
-
The value of
default_proc
must benil
. -
The value of
default
(which may be any object, includingnil
) will be returned for a not-found key.
You can set the default value when the hash is created with Hash.new
and option default_value
, or later with method default=
.
Note: although the value of default
may be any object, it may not be a good idea to use a mutable object.
Per-Key Defaults¶ ↑
You can define a per-key default for a hash; that is, a Proc
that will return a value based on the key itself.
You can set the default proc when the hash is created with Hash.new
and a block, or later with method default_proc=
.
Note that the proc can modify self
, but modifying self
in this way is not thread-safe; multiple threads can concurrently call into the default proc for the same key.
Method Default¶ ↑
For two methods, you can specify a default value for a not-found key that has effect only for a single method call (and not for any subsequent calls):
-
For method
fetch
, you can specify an any-key default: -
For either method
fetch
or methodfetch_values
, you can specify a per-key default via a block.
What’s Here¶ ↑
First, what’s elsewhere. Class Hash
:
-
Inherits from class Object.
-
Includes module Enumerable, which provides dozens of additional methods.
Here, class Hash
provides methods that are useful for:
Class Hash
also includes methods from module Enumerable
.
Methods for Creating a Hash
¶ ↑
-
::[]
: Returns a new hash populated with given objects. -
::new
: Returns a new empty hash. -
::try_convert
: Returns a new hash created from a given object.
Methods for Setting Hash
State¶ ↑
-
compare_by_identity
: Setsself
to consider only identity in comparing keys. -
default=
: Sets the default to a given value. -
default_proc=
: Sets the default proc to a given proc. -
rehash
: Rebuilds the hash table by recomputing the hash index for each key.
Methods for Querying¶ ↑
-
any?
: Returns whether any element satisfies a given criterion. -
compare_by_identity?
: Returns whether the hash considers only identity when comparing keys. -
default
: Returns the default value, or the default value for a given key. -
default_proc
: Returns the default proc. -
empty?
: Returns whether there are no entries. -
eql?
: Returns whether a given object is equal toself
. -
hash
: Returns the integer hash code. -
has_value?
(aliased asvalue?
): Returns whether a given object is a value inself
. -
include?
(aliased ashas_key?
,member?
,key?
): Returns whether a given object is a key inself
.
Methods for Comparing¶ ↑
-
<
: Returns whetherself
is a proper subset of a given object. -
<=
: Returns whetherself
is a subset of a given object. -
==
: Returns whether a given object is equal toself
. -
>
: Returns whetherself
is a proper superset of a given object -
>=
: Returns whetherself
is a superset of a given object.
Methods for Fetching¶ ↑
-
[]
: Returns the value associated with a given key. -
assoc
: Returns a 2-element array containing a given key and its value. -
dig
: Returns the object in nested objects that is specified by a given key and additional arguments. -
fetch
: Returns the value for a given key. -
fetch_values
: Returns array containing the values associated with given keys. -
key
: Returns the key for the first-found entry with a given value. -
keys
: Returns an array containing all keys inself
. -
rassoc
: Returns a 2-element array consisting of the key and value of the first-found entry having a given value. -
values
: Returns an array containing all values inself
/ -
values_at
: Returns an array containing values for given keys.
Methods for Assigning¶ ↑
-
[]=
(aliased asstore
): Associates a given key with a given value. -
merge
: Returns the hash formed by merging each given hash into a copy ofself
. -
update
(aliased asmerge!
): Merges each given hash intoself
. -
replace
(aliased asinitialize_copy
): Replaces the entire contents ofself
with the contents of a given hash.
Methods for Deleting¶ ↑
These methods remove entries from self
:
-
clear
: Removes all entries fromself
. -
compact!
: Removes allnil
-valued entries fromself
. -
delete
: Removes the entry for a given key. -
delete_if
: Removes entries selected by a given block. -
select!
(aliased asfilter!
): Keep only those entries selected by a given block. -
keep_if
: Keep only those entries selected by a given block. -
reject!
: Removes entries selected by a given block. -
shift
: Removes and returns the first entry.
These methods return a copy of self
with some entries removed:
-
compact
: Returns a copy ofself
with allnil
-valued entries removed. -
except
: Returns a copy ofself
with entries removed for specified keys. -
select
(aliased asfilter
): Returns a copy ofself
with only those entries selected by a given block. -
reject
: Returns a copy ofself
with entries removed as specified by a given block. -
slice
: Returns a hash containing the entries for given keys.
Methods for Iterating¶ ↑
-
each_pair
(aliased aseach
): Calls a given block with each key-value pair. -
each_key
: Calls a given block with each key. -
each_value
: Calls a given block with each value.
Methods for Converting¶ ↑
-
inspect
(aliased asto_s
): Returns a newString
containing the hash entries. -
to_a
: Returns a new array of 2-element arrays; each nested array contains a key-value pair fromself
. -
to_h
: Returnsself
if aHash
; if a subclass ofHash
, returns aHash
containing the entries fromself
. -
to_hash
: Returnsself
. -
to_proc
: Returns a proc that maps a given key to its value.
Methods for Transforming Keys and Values¶ ↑
-
transform_keys
: Returns a copy ofself
with modified keys. -
transform_keys!
: Modifies keys inself
-
transform_values
: Returns a copy ofself
with modified values. -
transform_values!
: Modifies values inself
.
Other Methods¶ ↑
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; }
Returns a new Hash object populated with the given objects, if any. See Hash::new
.
With no argument given, returns a new empty hash.
With a single argument other_hash
given that is a hash, returns a new hash initialized with the entries from that hash (but not with its default
or default_proc
):
h = {foo: 0, bar: 1, baz: 2} Hash[h] # => {foo: 0, bar: 1, baz: 2}
With a single argument 2_element_arrays
given that is an array of 2-element arrays, returns a new hash wherein each given 2-element array forms a key-value entry:
Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {foo: 0, bar: 1}
With an even number of arguments objects
given, returns a new hash wherein each successive pair of arguments is a key-value entry:
Hash[:foo, 0, :bar, 1] # => {foo: 0, bar: 1}
Raises ArgumentError
if the argument list does not conform to any of the above.
See also Methods for Creating a 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
Returns a new empty Hash object.
Initializes the values of Hash#default
and Hash#default_proc
, which determine the behavior when a given key is not found; see Key Not Found?.
By default, a hash has nil
values for both default
and default_proc
:
h = Hash.new # => {} h.default # => nil h.default_proc # => nil
With argument default_value
given, sets the default
value for the hash:
h = Hash.new(false) # => {} h.default # => false h.default_proc # => nil
With a block given, sets the default_proc
value:
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"
Raises ArgumentError
if both default_value
and a block are given.
If optional keyword argument capacity
is given with a positive integer value n
, initializes the hash with enough capacity to accommodate n
entries without resizing.
See also Methods for Creating a 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; }
Duplicates a given hash and adds a ruby2_keywords flag. This method is not for casual use; debugging, researching, and some truly necessary cases like deserialization of arguments.
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); }
Checks if a given hash is flagged by Module#ruby2_keywords
(or Proc#ruby2_keywords
). This method is not for casual use; debugging, researching, and some truly necessary cases like serialization of arguments.
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); }
If object
is a hash, returns object
.
Otherwise if object
responds to :to_hash
, calls object.to_hash
; returns the result if it is a hash, or raises TypeError
if not.
Otherwise if object
does not respond to :to_hash
, returns 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); }
Returns true
if the entries of self
are a proper subset of the entries of other_hash
, false
otherwise:
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.
See Hash Inclusion.
Raises TypeError
if other_hash
is not a hash and cannot be converted to a hash.
Related: see Methods for Comparing.
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); }
Returns true
if the entries of self
are a subset of the entries of other_hash
, false
otherwise:
h0 = {foo: 0, bar: 1} h1 = {foo: 0, bar: 1, baz: 2} h0 <= h0 # => true h0 <= h1 # => true h1 <= h0 # => false
See Hash Inclusion.
Raises TypeError
if other_hash
is not a hash and cannot be converted to a hash.
Related: see Methods for Comparing.
Source
static VALUE rb_hash_equal(VALUE hash1, VALUE hash2) { return hash_equal(hash1, hash2, FALSE); }
Returns whether self
and object
are equal.
Returns true
if all of the following are true:
-
object
is aHash
object (or can be converted to one). -
self
andobject
have the same keys (regardless of order). -
For each key
key
,self[key] == object[key]
.
Otherwise, returns false
.
Examples:
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.
Related: see Methods for Comparing.
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); }
Returns true
if the entries of self
are a proper superset of the entries of other_hash
, false
otherwise:
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.
See Hash Inclusion.
Raises TypeError
if other_hash
is not a hash and cannot be converted to a hash.
Related: see Methods for Comparing.
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); }
Returns true
if the entries of self
are a superset of the entries of other_hash
, false
otherwise:
h0 = {foo: 0, bar: 1, baz: 2} h1 = {foo: 0, bar: 1} h0 >= h1 # => true h0 >= h0 # => true h1 >= h0 # => false
See Hash Inclusion.
Raises TypeError
if other_hash
is not a hash and cannot be converted to a hash.
Related: see Methods for Comparing.
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); } }
Searches for a hash key equivalent to the given key
; see Hash Key Equivalence.
If the key is found, returns its value:
{foo: 0, bar: 1, baz: 2} h[:bar] # => 1
Otherwise, returns a default value (see Hash Default).
Related: []=
; see also Methods for Fetching.
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; }
Associates the given object
with the given key
; returns object
.
Searches for a hash key equivalent to the given key
; see Hash Key Equivalence.
If the key is found, replaces its value with the given object
; the ordering is not affected (see Entry Order):
h = {foo: 0, bar: 1} h[:foo] = 2 # => 2 h[:foo] # => 2
If key
is not found, creates a new entry for the given key
and object
; the new entry is last in the order (see Entry Order):
h = {foo: 0, bar: 1} h[:baz] = 2 # => 2 h[:baz] # => 2 h # => {:foo=>0, :bar=>1, :baz=>2}
Related: []
; see also Methods for Assigning.
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]; }
Returns true
if any element satisfies a given criterion; false
otherwise.
If self
has no element, returns false
and argument or block are not used; otherwise behaves as below.
With no argument and no block, returns true
if self
is non-empty, false
otherwise.
With argument entry
and no block, returns true
if for any key key
self.assoc(key) == entry
, false
otherwise:
h = {foo: 0, bar: 1, baz: 2} h.assoc(:bar) # => [:bar, 1] h.any?([:bar, 1]) # => true h.any?([:bar, 0]) # => false
With no argument and a block given, calls the block with each key-value pair; returns true
if the block returns a truthy value, false
otherwise:
h = {foo: 0, bar: 1, baz: 2} h.any? {|key, value| value < 3 } # => true h.any? {|key, value| value > 3 } # => false
With both argument entry
and a block given, issues a warning and ignores the block.
Related: Enumerable#any?
(which this method overrides); see also Methods for Fetching.
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]; }
If the given key
is found, returns its entry as a 2-element array containing that key and its value:
h = {foo: 0, bar: 1, baz: 2} h.assoc(:bar) # => [:bar, 1]
Returns nil
if the key is not found.
Related: see Methods for Fetching.
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; }
Removes all entries from self
; returns emptied self
.
Related: see Methods for Deleting.
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; }
Returns a copy of +self+ with all +nil+-valued entries removed: h = {foo: 0, bar: nil, baz: 2, bat: nil} h.compact # => {foo: 0, baz: 2}
Related: see Methods for Deleting.
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; }
If self
contains any nil
-valued entries, returns self
with all nil
-valued entries removed; returns nil
otherwise:
h = {foo: 0, bar: nil, baz: 2, bat: nil} h.compact! h # => {foo: 0, baz: 2} h.compact! # => nil
Related: see Methods for Deleting.
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; }
Sets self
to compare keys using identity (rather than mere equality); returns self
:
By default, two keys are considered to be the same key if and only if they are equal objects (per method ==
):
h = {} h['x'] = 0 h['x'] = 1 # Overwrites. h # => {"x"=>1}
When this method has been called, two keys are considered to be the same key if and only if they are the same object:
h.compare_by_identity h['x'] = 2 # Does not overwrite. h # => {"x"=>1, "x"=>2}
Related: compare_by_identity?
; see also Methods for Comparing.
Source
VALUE rb_hash_compare_by_id_p(VALUE hash) { return RBOOL(RHASH_IDENTHASH_P(hash)); }
Returns whether compare_by_identity
has been called:
h = {} h.compare_by_identity? # => false h.compare_by_identity h.compare_by_identity? # => true
Related: compare_by_identity
; see also Methods for Comparing.
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; }
Returns the default value for the given key
. The returned value will be determined either by the default proc or by the default value. See Hash Default.
With no argument, returns the current default value:
h = {} h.default # => nil
If key
is given, returns the default value for key
, regardless of whether that key exists:
h = Hash.new { |hash, key| hash[key] = "No key #{key}"} h[:foo] = "Hello" h.default(:foo) # => "No key foo"
Source
static VALUE rb_hash_set_default(VALUE hash, VALUE ifnone) { rb_hash_modify_check(hash); SET_DEFAULT(hash, ifnone); return ifnone; }
Sets the default value to value
; returns value
:
h = {} h.default # => nil h.default = false # => false h.default # => false
See Hash Default.
Source
static VALUE rb_hash_default_proc(VALUE hash) { if (FL_TEST(hash, RHASH_PROC_DEFAULT)) { return RHASH_IFNONE(hash); } return Qnil; }
Returns the default proc for self
(see Hash Default):
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; }
Sets the default proc for self
to proc
(see Hash Default):
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; } } }
If an entry for the given key
is found, deletes the entry and returns its associated value; otherwise returns nil
or calls the given block.
With no block given and key
found, deletes the entry and returns its value:
h = {foo: 0, bar: 1, baz: 2} h.delete(:bar) # => 1 h # => {foo: 0, baz: 2}
With no block given and key
not found, returns nil
.
With a block given and key
found, ignores the block, deletes the entry, and returns its value:
h = {foo: 0, bar: 1, baz: 2} h.delete(:baz) { |key| raise 'Will never happen'} # => 2 h # => {foo: 0, bar: 1}
With a block given and key
not found, calls the block and returns the block’s return value:
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}
Related: see Methods for Deleting.
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; }
With a block given, calls the block with each key-value pair, deletes each entry for which the block returns a truthy value, and returns self
:
h = {foo: 0, bar: 1, baz: 2} h.delete_if {|key, value| value > 0 } # => {foo: 0}
With no block given, returns a new Enumerator
.
Related: see Methods for Deleting.
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); }
Finds and returns an object found in nested objects, as specified by key
and identifiers
.
The nested objects may be instances of various classes. See Dig Methods.
Nested hashes:
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
Nested hashes and arrays:
h = {foo: {bar: [:a, :b, :c]}} h.dig(:foo, :bar, 2) # => :c
If no such object is found, returns the hash default:
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]}}
Related: Methods for Fetching.
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; }
With a block given, calls the block with each key; returns self
:
h = {foo: 0, bar: 1, baz: 2} h.each_key {|key| puts key } # => {foo: 0, bar: 1, baz: 2}
Output:
foo bar baz
With no block given, returns a new Enumerator
.
Related: see Methods for Iterating.
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; }
With a block given, calls the block with each key-value pair; returns self
:
h = {foo: 0, bar: 1, baz: 2} h.each_pair {|key, value| puts "#{key}: #{value}"} # => {foo: 0, bar: 1, baz: 2}
Output:
foo: 0 bar: 1 baz: 2
With no block given, returns a new Enumerator
.
Related: see Methods for Iterating.
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; }
With a block given, calls the block with each value; returns self
:
h = {foo: 0, bar: 1, baz: 2} h.each_value {|value| puts value } # => {foo: 0, bar: 1, baz: 2}
Output:
0 1 2
With no block given, returns a new Enumerator
.
Related: see Methods for Iterating.
Source
VALUE rb_hash_empty_p(VALUE hash) { return RBOOL(RHASH_EMPTY_P(hash)); }
Returns true
if there are no hash entries, false
otherwise:
{}.empty? # => true {foo: 0}.empty? # => false
Related: see Methods for Querying.
Source
static VALUE rb_hash_eql(VALUE hash1, VALUE hash2) { return hash_equal(hash1, hash2, TRUE); }
Returns true
if all of the following are true:
-
The given
object
is aHash
object. -
self
andobject
have the same keys (regardless of order). -
For each key
key
,self[key].eql?(object[key])
.
Otherwise, returns 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
Related: see Methods for Querying.
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; }
Returns a copy of self
that excludes entries for the given keys
; any keys
that are not found are ignored:
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}
Related: see Methods for Deleting.
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]; } } }
With no block given, returns the value for the given key
, if found;
h = {foo: 0, bar: 1, baz: 2} h.fetch(:bar) # => 1
If the key is not found, returns default_value
, if given, or raises KeyError
otherwise:
h.fetch(:nosuch, :default) # => :default h.fetch(:nosuch) # Raises KeyError.
With a block given, calls the block with key
and returns the block’s return value:
{}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch"
Note that this method does not use the values of either default
or default_proc
.
Related: see Methods for Fetching.
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; }
Returns a new Array
containing the values associated with the given keys *keys:
h = {foo: 0, bar: 1, baz: 2} h.fetch_values(:baz, :foo) # => [2, 0]
Returns a new empty Array
if no arguments given.
When a block is given, calls the block with each missing key, treating the block’s return value as the value for that key:
h = {foo: 0, bar: 1, baz: 2} values = h.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s} values # => [1, 0, "bad", "bam"]
When no block is given, raises an exception if any given key is not found.
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; }
Returns a new Array
object that is a 1-dimensional flattening of self
.
By default, nested Arrays are not flattened:
h = {foo: 0, bar: [:bat, 3], baz: 2} h.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2]
Takes the depth of recursive flattening from Integer
argument 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]
When level
is negative, flattens all nested Arrays:
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]
When level
is zero, returns the equivalent of 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
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); }
Returns the Integer
hash-code for the hash.
Two Hash
objects have the same hash-code if their content is the same (regardless of order):
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)); }
Returns true
if key
is a key in self
, otherwise false
.
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); }
Returns a new String
containing the hash entries:
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; }
Returns a new Hash
object with the each key-value pair inverted:
h = {foo: 0, bar: 1, baz: 2} h1 = h.invert h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
Overwrites any repeated new keys: (see Entry Order):
h = {foo: 0, bar: 0, baz: 0} h.invert # => {0=>:baz}
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; }
Calls the block for each key-value pair; retains the entry if the block returns a truthy value; otherwise deletes the entry; returns self
.
h = {foo: 0, bar: 1, baz: 2} h.keep_if { |key, value| key.start_with?('b') } # => {bar: 1, baz: 2}
Returns a new Enumerator
if no block given:
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}
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]; }
Returns the key for the first-found entry with the given value
(see Entry Order):
h = {foo: 0, bar: 2, baz: 2} h.key(0) # => :foo h.key(2) # => :bar
Returns nil
if no such value is found.
Returns true
if key
is a key in self
, otherwise false
.
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; }
Returns a new Array
containing all keys in self
:
h = {foo: 0, bar: 1, baz: 2} h.keys # => [:foo, :bar, :baz]
Returns the count of entries in self
:
{foo: 0, bar: 1, baz: 2}.length # => 3
Returns true
if key
is a key in self
, otherwise false
.
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)); }
Returns the new Hash
formed by merging each of other_hashes
into a copy of self
.
Each argument in other_hashes
must be a Hash
.
With arguments and no block:
-
Returns the new
Hash
object formed by merging each successiveHash
inother_hashes
intoself
. -
Each new-key entry is added at the end.
-
Each duplicate-key entry’s value overwrites the previous value.
Example:
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}
With arguments and a block:
-
Returns a new
Hash
object that is the merge ofself
and each given hash. -
The given hashes are merged left to right.
-
Each new-key entry is added at the end.
-
For each duplicate key:
-
Calls the block with the key and the old and new values.
-
The block’s return value becomes the new value for the entry.
-
Example:
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}
With no arguments:
-
Returns a copy of
self
. -
The block, if given, is ignored.
Example:
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}
Merges each of other_hashes
into self
; returns self
.
Each argument in other_hashes
must be a Hash
.
With arguments and no block:
-
Returns
self
, after the given hashes are merged into it. -
The given hashes are merged left to right.
-
Each new entry is added at the end.
-
Each duplicate-key entry’s value overwrites the previous value.
Example:
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}
With arguments and a block:
-
Returns
self
, after the given hashes are merged. -
The given hashes are merged left to right.
-
Each new-key entry is added at the end.
-
For each duplicate key:
-
Calls the block with the key and the old and new values.
-
The block’s return value becomes the new value for the entry.
-
Example:
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}
With no arguments:
-
Returns
self
, unmodified. -
The block, if given, is ignored.
Example:
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}
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]; }
Returns a new 2-element Array
consisting of the key and value of the first-found entry whose value is ==
to value (see Entry Order):
h = {foo: 0, bar: 1, baz: 1} h.rassoc(1) # => [:bar, 1]
Returns nil
if no such value found.
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; }
Rebuilds the hash table by recomputing the hash index for each key; returns self
.
The hash table becomes invalid if the hash value of a key has changed after the entry was created. See Modifying an Active Hash Key.
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; }
Returns a new Hash
object whose entries are all those from self
for which the block returns false
or nil
:
h = {foo: 0, bar: 1, baz: 2} h1 = h.reject {|key, value| key.start_with?('b') } h1 # => {foo: 0}
Returns a new Enumerator
if no block given:
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}
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; }
Returns self
, whose remaining entries are those for which the block returns false
or nil
:
h = {foo: 0, bar: 1, baz: 2} h.reject! {|key, value| value < 2 } # => {baz: 2}
Returns nil
if no entries are removed.
Returns a new Enumerator
if no block given:
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}
Replaces the entire contents of self
with the contents of other_hash
; returns self
:
h = {foo: 0, bar: 1, baz: 2} h.replace({bat: 3, bam: 4}) # => {bat: 3, bam: 4}
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; }
Returns a new Hash
object whose entries are those for which the block returns a truthy value:
h = {foo: 0, bar: 1, baz: 2} h.select {|key, value| value < 2 } # => {foo: 0, bar: 1}
Returns a new Enumerator
if no block given:
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}
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; }
Returns self
, whose entries are those for which the block returns a truthy value:
h = {foo: 0, bar: 1, baz: 2} h.select! {|key, value| value < 2 } => {foo: 0, bar: 1}
Returns nil
if no entries were removed.
Returns a new Enumerator
if no block given:
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}
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; }
Removes the first hash entry (see Entry Order); returns a 2-element Array
containing the removed key and value:
h = {foo: 0, bar: 1, baz: 2} h.shift # => [:foo, 0] h # => {bar: 1, baz: 2}
Returns nil if the hash is empty.
Source
VALUE rb_hash_size(VALUE hash) { return INT2FIX(RHASH_SIZE(hash)); }
Returns the count of entries in self
:
{foo: 0, bar: 1, baz: 2}.length # => 3
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; }
Returns a new Hash
object containing the entries for the given keys
:
h = {foo: 0, bar: 1, baz: 2} h.slice(:baz, :foo) # => {baz: 2, foo: 0}
Any given keys
that are not found are ignored.
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; }
Returns a new Array
of 2-element Array
objects; each nested Array
contains a key-value pair from 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; }
For an instance of Hash
, returns self
.
For a subclass of Hash
, returns a new Hash
containing the content of self
.
When a block is given, returns a new Hash
object whose content is based on the block; the block should return a 2-element Array
object specifying the key-value pair to be included in the returned Array:
h = {foo: 0, bar: 1, baz: 2} h1 = h.to_h {|key, value| [value, key] } h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
Source
static VALUE rb_hash_to_proc(VALUE hash) { return rb_func_lambda_new(hash_proc_call, hash, 1, 1); }
Returns a Proc
object that maps a key to its value:
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
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; }
Returns a new Hash
object; each entry has:
-
A key provided by the block.
-
The value from
self
.
An optional hash argument can be provided to map keys to new keys. Any key not given will be mapped using the provided block, or remain the same if no block is given.
Transform keys:
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}
Overwrites values for duplicate keys:
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_keys {|key| :bat } h1 # => {bat: 2}
Returns a new Enumerator
if no block given:
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}
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; }
Same as Hash#transform_keys
but modifies the receiver in place instead of returning a new hash.
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)) { rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result); compact_after_delete(result); } return result; }
Returns a new Hash
object; each entry has:
-
A key from
self
. -
A value provided by the block.
Transform values:
h = {foo: 0, bar: 1, baz: 2} h1 = h.transform_values {|value| value * 100} h1 # => {foo: 0, bar: 100, baz: 200}
Returns a new Enumerator
if no block given:
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}
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)) { rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash); } return hash; }
Returns self
, whose keys are unchanged, and whose values are determined by the given block.
h = {foo: 0, bar: 1, baz: 2} h.transform_values! {|value| value * 100} # => {foo: 0, bar: 100, baz: 200}
Returns a new Enumerator
if no block given:
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}
Returns true
if value
is a value in self
, otherwise false
.
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; }
Returns a new Array
containing all values in self
:
h = {foo: 0, bar: 1, baz: 2} h.values # => [0, 1, 2]
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; }
Returns a new Array
containing values for the given keys
:
h = {foo: 0, bar: 1, baz: 2} h.values_at(:baz, :foo) # => [2, 0]
The hash default is returned for each key that is not found:
h.values_at(:hello, :foo) # => [nil, 0]