class Hash
A Hash object maps each of its unique keys to a specific value.
A hash has certain similarities to anArray, but:
An array index is always an integer.
A hash key can be (almost) any object.
Hash Data Syntax¶↑
The original syntax for a hash entry uses the “hash rocket,”=>:
h = {:foo=>0,:bar=>1,:baz=>2}h# => {foo: 0, bar: 1, baz: 2}
Alternatively, but only for a 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'}The value can be omitted, meaning that value will be fetched from the context by the name of the key:
x =0y =100h = {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:
defsome_method(hash)phashendsome_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:
classDevattr_accessor:name,:languagedefinitialize(hash)self.name =hash[:name]self.language =hash[:language]endendmatz =Dev.new(name:'Matz',language:'Ruby')matz# => #<Dev: @name="Matz", @language="Ruby">
Creating a Hash¶↑
You can create a Hash object explicitly with:
You can convert certain objects to hashes with:
Method
Kernel#Hash.
You can create a hash by calling methodHash.new:
# Create an empty hash.h =Hash.newh# => {}h.class# => Hash
You can create a hash by calling methodHash.[]:
# 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# => 3h# => {foo: 0, bar: 1, baz: 2, bat: 3}h[:foo] =4# => 4h# => {foo: 4, bar: 1, baz: 2, bat: 3}
The simplest way to delete a hash entry (instance methoddelete):
h = {foo:0,bar:1,baz:2}h.delete(:bar)# => 1h# => {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 method
inspect.
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] =2h# => {foo: 0, bar: 1, baz: 2}
Updating a value does not affect the order:
h[:baz] =3h# => {foo: 0, bar: 1, baz: 3}
But re-creating a deleted entry can affect the order:
h.delete(:foo)h[:foo] =5h# => {bar: 1, baz: 3, foo: 5}
Hash Keys¶↑
Hash Key Equivalence¶↑
Two objects are treated as the same hash key when theirhash value is identical and the two objects areeql? to each other.
Modifying an ActiveHash Key¶↑
Modifying aHash key while it is in use damages the hash’s index.
ThisHash has keys that are Arrays:
a0 = [:foo,:bar ]a1 = [:baz,:bat ]h = {a0=>0,a1=>1}h.include?(a0)# => trueh[a0]# => 0a0.hash# => 110002110
Modifying array elementa0[0] changes its hash value:
a0[0] =:bama0.hash# => 1069447059
And damages theHash index:
h.include?(a0)# => falseh[a0]# => nil
You can repair the hash index using methodrehash:
h.rehash# => {[:bam, :bar]=>0, [:baz, :bat]=>1}h.include?(a0)# => trueh[a0]# => 0
AString key is always safe. That’s because an unfrozenString passed as a key will be replaced by a duplicated and frozen String:
s ='foo's.frozen?# => falseh = {s=>0}first_key =h.keys.firstfirst_key.frozen?# => true
User-DefinedHash Keys¶↑
To be usable as aHash key, objects must implement the methodshash andeql?. Note: this requirement does not apply if theHash usescompare_by_identity since comparison will then rely on the keys’ object id instead ofhash andeql?.
Object defines basic implementation forhash andeq? that makes each object a distinct key. Typically, user-defined classes will want to override these methods to provide meaningful behavior, or for example inheritStruct that has useful definitions for these.
A typical implementation ofhash is based on the object’s data whileeql? is usually aliased to the overridden== method:
classBookattr_reader:author,:titledefinitialize(author,title)@author =author@title =titleenddef==(other)self.class===other&&other.author==@author&&other.title==@titleendaliaseql?==defhash [self.class,@author,@title].hashendendbook1 =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 keyis found, the returned value is the value associated with the key.
But what if the keyis not found? In that case, certain methods will return a default value while other will raise a KeyError.
Nil Return Value¶↑
If you wantnil returned for a not-found key, you can call:
[](key)(usually written as#[key].
You can override these behaviors for[],dig, andvalues_at (but notassoc); seeHash Default.
KeyError¶↑
If you wantKeyError raised for a not-found key, you can call:
Hash Default¶↑
For certain methods ([],dig, andvalues_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 arenil, and the methods returnnil for a not-found key; seeNil Return Value above.
Note that this entire section (“Hash Default”):
Doesnot 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 forany not-found key:
The value of
default_procmust 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 withHash.new and optiondefault_value, or later with methoddefault=.
Note: although the value ofdefault 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, aProc that will return a value based on the key itself.
You can set the default proc when the hash is created withHash.new and a block, or later with methoddefault_proc=.
Note that the proc can modifyself, but modifyingself 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
fetchor methodfetch_values, you can specify a per-key default via a block.
What’s Here¶↑
First, what’s elsewhere. ClassHash:
Inherits fromclass Object.
Includesmodule Enumerable, which provides dozens of additional methods.
Here, classHash provides methods that are useful for:
ClassHash also includes methods from moduleEnumerable.
Methods for Creating aHash¶↑
::[]: 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 SettingHash State¶↑
compare_by_identity: Setsselfto 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 whetherselfis a proper subset of a given object.<=: Returns whetherselfis a subset of a given object.==: Returns whether a given object is equal toself.>: Returns whetherselfis a proper superset of a given object>=: Returns whetherselfis 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.replace(aliased asinitialize_copy): Replaces the entire contents ofselfwith the contents of a given hash.
Methods for Deleting¶↑
These methods remove entries fromself:
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 ofself with some entries removed:
compact: Returns a copy ofselfwith allnil-valued entries removed.except: Returns a copy ofselfwith entries removed for specified keys.select(aliased asfilter): Returns a copy ofselfwith only those entries selected by a given block.reject: Returns a copy ofselfwith 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¶↑
flatten: Returns an array that is a 1-dimensional flattening ofself.inspect(aliased asto_s): Returns a newStringcontaining the hash entries.to_a: Returns a new array of 2-element arrays; each nested array contains a key-value pair fromself.to_h: Returnsselfif aHash; if a subclass ofHash, returns aHashcontaining 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¶↑
invert: Returns a hash with the each key-value pair inverted.transform_keys: Returns a copy ofselfwith modified keys.transform_keys!: Modifies keys inselftransform_values: Returns a copy ofselfwith modified values.transform_values!: Modifies values inself.
Public Class Methods
Source
static VALUErb_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. SeeHash::new.
With no argument given, returns a new empty hash.
With a single argumentother_hash given that is a hash, returns a new hash initialized with the entries from that hash (but not with itsdefault ordefault_proc):
h = {foo:0,bar:1,baz:2}Hash[h]# => {foo: 0, bar: 1, baz: 2}
With a single argument2_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 argumentsobjects 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}
RaisesArgumentError if the argument list does not conform to any of the above.
See alsoMethods for Creating a Hash.
Source
# File hash.rb, line 37definitialize(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 ofHash#default andHash#default_proc, which determine the behavior when a given key is not found; seeKey Not Found?.
By default, a hash hasnil values for bothdefault anddefault_proc:
h =Hash.new# => {}h.default# => nilh.default_proc# => nil
With argumentdefault_value given, sets thedefault value for the hash:
h =Hash.new(false)# => {}h.default# => falseh.default_proc# => nil
With a block given, sets thedefault_proc value:
h =Hash.new {|hash,key|"Hash #{hash}: Default value for #{key}" }h.default# => nilh.default_proc# => #<Proc:0x00000289b6fa7048 (irb):185>h[:nosuch]# => "Hash {}: Default value for nosuch"
RaisesArgumentError if bothdefault_value and a block are given.
If optional keyword argumentcapacity is given with a positive integer valuen, initializes the hash with enough capacity to accommodaten entries without resizing.
See alsoMethods for Creating a Hash.
Source
static VALUErb_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)deffoo(k:42)kendfoo(*[h])#=> 1 with neither a warning or an error
Source
static VALUErb_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 byModule#ruby2_keywords (orProc#ruby2_keywords). This method is not for casual use; debugging, researching, and some truly necessary cases like serialization of arguments.
ruby2_keywordsdeffoo(*args)Hash.ruby2_keywords_hash?(args.last)endfoo(k:1)#=> truefoo({k:1})#=> false
Source
static VALUErb_hash_s_try_convert(VALUE dummy, VALUE hash){ return rb_check_hash_type(hash);}Ifobject is a hash, returnsobject.
Otherwise ifobject responds to:to_hash, callsobject.to_hash; returns the result if it is a hash, or raisesTypeError if not.
Otherwise ifobject does not respond to:to_hash, returnsnil.
Public Instance Methods
Source
static VALUErb_hash_lt(VALUE hash, VALUE other){ other = to_hash(other); if (RHASH_SIZE(hash) >= RHASH_SIZE(other)) return Qfalse; return hash_le(hash, other);}Returnstrue if the entries ofself are a proper subset of the entries ofother_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.
SeeHash Inclusion.
RaisesTypeError ifother_hash is not a hash and cannot be converted to a hash.
Related: seeMethods for Comparing.
Source
static VALUErb_hash_le(VALUE hash, VALUE other){ other = to_hash(other); if (RHASH_SIZE(hash) > RHASH_SIZE(other)) return Qfalse; return hash_le(hash, other);}Returnstrue if the entries ofself are a subset of the entries ofother_hash,false otherwise:
h0 = {foo:0,bar:1}h1 = {foo:0,bar:1,baz:2}h0<=h0# => trueh0<=h1# => trueh1<=h0# => false
SeeHash Inclusion.
RaisesTypeError ifother_hash is not a hash and cannot be converted to a hash.
Related: seeMethods for Comparing.
Source
static VALUErb_hash_equal(VALUE hash1, VALUE hash2){ return hash_equal(hash1, hash2, FALSE);}Returns whetherself andobject are equal.
Returnstrue if all of the following are true:
objectis aHashobject (or can be converted to one).selfandobjecthave the same keys (regardless of order).For each key
key,self[key] == object[key].
Otherwise, returnsfalse.
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: seeMethods for Comparing.
Source
static VALUErb_hash_gt(VALUE hash, VALUE other){ other = to_hash(other); if (RHASH_SIZE(hash) <= RHASH_SIZE(other)) return Qfalse; return hash_le(other, hash);}Returnstrue if the entries ofself are a proper superset of the entries ofother_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.
SeeHash Inclusion.
RaisesTypeError ifother_hash is not a hash and cannot be converted to a hash.
Related: seeMethods for Comparing.
Source
static VALUErb_hash_ge(VALUE hash, VALUE other){ other = to_hash(other); if (RHASH_SIZE(hash) < RHASH_SIZE(other)) return Qfalse; return hash_le(other, hash);}Returnstrue if the entries ofself are a superset of the entries ofother_hash,false otherwise:
h0 = {foo:0,bar:1,baz:2}h1 = {foo:0,bar:1}h0>=h1# => trueh0>=h0# => trueh1>=h0# => false
SeeHash Inclusion.
RaisesTypeError ifother_hash is not a hash and cannot be converted to a hash.
Related: seeMethods for Comparing.
Source
VALUErb_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 givenkey; seeHash Key Equivalence.
If the key is found, returns its value:
{foo:0,bar:1,baz:2}h[:bar]# => 1Otherwise, returns a default value (seeHash Default).
Related:[]=; see alsoMethods for Fetching.
Source
VALUErb_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 givenobject with the givenkey; returnsobject.
Searches for a hash key equivalent to the givenkey; seeHash Key Equivalence.
If the key is found, replaces its value with the givenobject; the ordering is not affected (seeEntry Order):
h = {foo:0,bar:1}h[:foo] =2# => 2h[:foo]# => 2
Ifkey is not found, creates a new entry for the givenkey andobject; the new entry is last in the order (seeEntry Order):
h = {foo:0,bar:1}h[:baz] =2# => 2h[:baz]# => 2h# => {:foo=>0, :bar=>1, :baz=>2}
Related:[]; see alsoMethods for Assigning.
Source
static VALUErb_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];}Returnstrue if any element satisfies a given criterion;false otherwise.
Ifself has no element, returnsfalse and argument or block are not used; otherwise behaves as below.
With no argument and no block, returnstrue ifself is non-empty,false otherwise.
With argumententry and no block, returnstrue if for any keykeyself.assoc(key) == entry,false otherwise:
h = {foo:0,bar:1,baz:2}h.assoc(:bar)# => [:bar, 1]h.any?([:bar,1])# => trueh.any?([:bar,0])# => false
With no argument and a block given, calls the block with each key-value pair; returnstrue if the block returns a truthy value,false otherwise:
h = {foo:0,bar:1,baz:2}h.any? {|key,value|value<3 }# => trueh.any? {|key,value|value>3 }# => false
With both argumententry and a block given, issues a warning and ignores the block.
Related:Enumerable#any? (which this method overrides); see alsoMethods for Fetching.
Source
static VALUErb_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 givenkey 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]
Returnsnil if the key is not found.
Related: seeMethods for Fetching.
Source
VALUErb_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 fromself; returns emptiedself.
Related: seeMethods for Deleting.
Source
static VALUErb_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 ofself with allnil-valued entries removed:
h = {foo:0,bar:nil,baz:2,bat:nil}h.compact# => {foo: 0, baz: 2}
Related: seeMethods for Deleting.
Source
static VALUErb_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;}Ifself contains anynil-valued entries, returnsself with allnil-valued entries removed; returnsnil otherwise:
h = {foo:0,bar:nil,baz:2,bat:nil}h.compact!h# => {foo: 0, baz: 2}h.compact!# => nil
Related: seeMethods for Deleting.
Source
VALUErb_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;}Setsself to compare keys usingidentity (rather than mereequality); returnsself:
By default, two keys are considered to be the same key if and only if they areequal objects (per methodeql?):
h = {}h['x'] =0h['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 thesame object:
h.compare_by_identityh['x'] =2# Does not overwrite.h# => {"x"=>1, "x"=>2}
Related:compare_by_identity?; see alsoMethods for Comparing.
Source
VALUErb_hash_compare_by_id_p(VALUE hash){ return RBOOL(RHASH_IDENTHASH_P(hash));}Returns whethercompare_by_identity has been called:
h = {}h.compare_by_identity?# => falseh.compare_by_identityh.compare_by_identity?# => true
Related:compare_by_identity; see alsoMethods for Comparing.
Source
static VALUErb_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 givenkey. The returned value will be determined either by the default proc or by the default value. SeeHash Default.
With no argument, returns the current default value:
h = {}h.default# => nil
Ifkey is given, returns the default value forkey, 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
VALUErb_hash_set_default(VALUE hash, VALUE ifnone){ rb_hash_modify_check(hash); SET_DEFAULT(hash, ifnone); return ifnone;}Sets the default value tovalue; returnsvalue:
h = {}h.default# => nilh.default =false# => falseh.default# => false
SeeHash Default.
Source
static VALUErb_hash_default_proc(VALUE hash){ if (FL_TEST(hash, RHASH_PROC_DEFAULT)) { return RHASH_IFNONE(hash); } return Qnil;}Returns the default proc forself (seeHash Default):
h = {}h.default_proc# => nilh.default_proc =proc {|hash,key|"Default value for #{key}" }h.default_proc.class# => Proc
Source
VALUErb_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 forself toproc (seeHash Default):
h = {}h.default_proc# => nilh.default_proc =proc {|hash,key|"Default value for #{key}" }h.default_proc.class# => Proch.default_proc =nilh.default_proc# => nil
Source
static VALUErb_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 givenkey is found, deletes the entry and returns its associated value; otherwise returnsnil or calls the given block.
With no block given andkey found, deletes the entry and returns its value:
h = {foo:0,bar:1,baz:2}h.delete(:bar)# => 1h# => {foo: 0, baz: 2}
With no block given andkey not found, returnsnil.
With a block given andkey 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'}# => 2h# => {foo: 0, bar: 1}
With a block given andkey 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: seeMethods for Deleting.
Source
VALUErb_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 returnsself:
h = {foo:0,bar:1,baz:2}h.delete_if {|key,value|value>0 }# => {foo: 0}
With no block given, returns a newEnumerator.
Related: seeMethods for Deleting.
Source
static VALUErb_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 bykey andidentifiers.
The nested objects may be instances of various classes. SeeDig 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)# => 2h.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 thehash default:
h = {foo: {bar: [:a,:b,:c]}}h.dig(:hello)# => nilh.default_proc =-> (hash,_key) {hash }h.dig(:hello,:world)# => {:foo=>{:bar=>[:a, :b, :c]}}
Related:Methods for Fetching.
Source
static VALUErb_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; returnsself:
h = {foo:0,bar:1,baz:2}h.each_key {|key|putskey }# => {foo: 0, bar: 1, baz: 2}
Output:
foobarbaz
With no block given, returns a newEnumerator.
Related: seeMethods for Iterating.
Source
static VALUErb_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; returnsself:
h = {foo:0,bar:1,baz:2}h.each_pair {|key,value|puts"#{key}: #{value}"}# => {foo: 0, bar: 1, baz: 2}
Output:
foo: 0bar: 1baz: 2
With no block given, returns a newEnumerator.
Related: seeMethods for Iterating.
Source
static VALUErb_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; returnsself:
h = {foo:0,bar:1,baz:2}h.each_value {|value|putsvalue }# => {foo: 0, bar: 1, baz: 2}
Output:
012
With no block given, returns a newEnumerator.
Related: seeMethods for Iterating.
Source
VALUErb_hash_empty_p(VALUE hash){ return RBOOL(RHASH_EMPTY_P(hash));}Returnstrue if there are no hash entries,false otherwise:
{}.empty?# => true{foo:0}.empty?# => falseRelated: seeMethods for Querying.
Source
static VALUErb_hash_eql(VALUE hash1, VALUE hash2){ return hash_equal(hash1, hash2, TRUE);}Returnstrue if all of the following are true:
The given
objectis aHashobject.selfandobjecthave the same keys (regardless of order).For each key
key,self[key].eql?(object[key]).
Otherwise, returnsfalse.
h1 = {foo:0,bar:1,baz:2}h2 = {foo:0,bar:1,baz:2}h1.eql?h2# => trueh3 = {baz:2,bar:1,foo:0}h1.eql?h3# => true
Related: seeMethods for Querying.
Source
static VALUErb_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 ofself that excludes entries for the givenkeys; anykeys 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: seeMethods for Deleting.
Source
static VALUErb_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 givenkey, if found;
h = {foo:0,bar:1,baz:2}h.fetch(:bar)# => 1
If the key is not found, returnsdefault_value, if given, or raisesKeyError otherwise:
h.fetch(:nosuch,:default)# => :defaulth.fetch(:nosuch)# Raises KeyError.
With a block given, calls the block withkey 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 eitherdefault ordefault_proc.
Related: seeMethods for Fetching.
Source
static VALUErb_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;}When all givenkeys are found, returns a new array containing the values associated with the givenkeys:
h = {foo:0,bar:1,baz:2}h.fetch_values(:baz,:foo)# => [2, 0]
When any givenkeys are not found and a block is given, calls the block with each unfound key and uses the block’s return value as the value for that key:
h.fetch_values(:bar,:foo,:bad,:bam) {|key|key.to_s}# => [1, 0, "bad", "bam"]
When any givenkeys are not found and no block is given, raisesKeyError.
Related: seeMethods for Fetching.
Source
static VALUErb_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;}With positive integerdepth, returns a new array that is a recursive flattening ofself to the givendepth.
At each level of recursion:
Each element whose value is an array is “flattened” (that is, replaced by its individual array elements); see
Array#flatten.Each element whose value is not an array is unchanged. even if the value is an object that has instance method flatten (such as a hash).
Examples; note that entryfoo: {bar: 1, baz: 2} is never flattened.
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]
With negative integerdepth, flattens all levels:
h.flatten(-1)# => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah]
Withdepth zero, returns the equivalent ofto_a:
h.flatten(0)# => [[:foo, {:bar=>1, :baz=>2}], [:bat, [:bam, [:bap, [:bah]]]]]
Related: seeMethods for Converting.
Source
static VALUErb_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 hashes 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# => trueh2.eql?h1# => true
Related: seeMethods for Querying.
Source
VALUErb_hash_has_key(VALUE hash, VALUE key){ return RBOOL(hash_stlike_lookup(hash, key, NULL));}Returns whetherkey is a key inself:
h = {foo:0,bar:1,baz:2}h.include?(:bar)# => trueh.include?(:BAR)# => false
Related:Methods for Querying.
Source
static VALUErb_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}"
Related: seeMethods for Converting.
Source
static VALUErb_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 with each key-value pair inverted:
h = {foo:0,bar:1,baz:2}h1 =h.inverth1# => {0=>:foo, 1=>:bar, 2=>:baz}
Overwrites any repeated new keys (seeEntry Order):
h = {foo:0,bar:0,baz:0}h.invert# => {0=>:baz}
Related: seeMethods for Transforming Keys and Values.
Source
static VALUErb_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;}With a block given, calls the block for each key-value pair; retains the entry if the block returns a truthy value; otherwise deletes the entry; returnsself:
h = {foo:0,bar:1,baz:2}h.keep_if {|key,value|key.start_with?('b') }# => {bar: 1, baz: 2}
With no block given, returns a newEnumerator.
Related: seeMethods for Deleting.
Source
static VALUErb_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 givenvalue (seeEntry Order):
h = {foo:0,bar:2,baz:2}h.key(0)# => :fooh.key(2)# => :bar
Returnsnil if no such value is found.
Related: seeMethods for Fetching.
Source
VALUErb_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 inself:
h = {foo:0,bar:1,baz:2}h.keys# => [:foo, :bar, :baz]
Related: seeMethods for Fetching.
Source
static VALUErb_hash_merge(int argc, VALUE *argv, VALUE self){ return rb_hash_update(argc, argv, copy_compare_by_id(rb_hash_dup(self), self));}Each argumentother_hash inother_hashes must be a hash.
With argumentsother_hashes given and no block, returns the new hash formed by merging each successiveother_hash into a copy ofself; returns that copy; for each successive entry inother_hash:
For a new key, the entry is added at the end of
self.For duplicate key, the entry overwrites the entry in
self, whose position is unchanged.
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 argumentsother_hashes and a block given, behaves as above except that for a duplicate key the overwriting entry takes it value not from the entry inother_hash, but instead from the block:
The block is called with the duplicate key and the values from both
selfandother_hash.The block’s return value becomes the new value for the entry in
self.
Example:
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}
With no arguments, returns a copy ofself; the block, if given, is ignored.
Related: seeMethods for Assigning.
Source
static VALUErb_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];}Searchesself for the first entry whose value is== to the givenvalue; seeEntry Order.
If the entry is found, returns its key and value as a 2-element array; returnsnil if not found:
h = {foo:0,bar:1,baz:1}h.rassoc(1)# => [:bar, 1]
Related: seeMethods for Fetching.
Source
VALUErb_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 forself by recomputing the hash index for each key; returnsself. Calling this method ensures that the hash table is valid.
The hash table becomes invalid if the hash value of a key has changed after the entry was created. SeeModifying an Active Hash Key.
Source
static VALUErb_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;}With a block given, returns a copy ofself with zero or more entries removed; calls the block with each key-value pair; excludes the entry in the copy if the block returns a truthy value, includes it otherwise:
h = {foo:0,bar:1,baz:2}h.reject {|key,value|key.start_with?('b') }# => {foo: 0}
With no block given, returns a newEnumerator.
Related: seeMethods for Deleting.
Source
static VALUErb_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;}With a block given, calls the block with each entry’s key and value; removes the entry fromself if the block returns a truthy value.
Returnself if any entries were removed,nil otherwise:
h = {foo:0,bar:1,baz:2}h.reject! {|key,value|value<2 }# => {baz: 2}h.reject! {|key,value|value<2 }# => nil
With no block given, returns a newEnumerator.
Related: seeMethods for Deleting.
Replaces the entire contents ofself with the contents ofother_hash; returnsself:
h = {foo:0,bar:1,baz:2}h.replace({bat:3,bam:4})# => {bat: 3, bam: 4}
Also replaces the default value or proc ofself with the default value or proc ofother_hash.
h = {}other =Hash.new(:ok)h.replace(other)h.default# => :ok
Related: seeMethods for Assigning.
Source
static VALUErb_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;}With a block given, calls the block with each entry’s key and value; returns a new hash 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}
With no block given, returns a newEnumerator.
Related: seeMethods for Deleting.
Source
static VALUErb_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;}With a block given, calls the block with each entry’s key and value; removes fromself each entry for which the block returnsfalse ornil.
Returnsself if any entries were removed,nil otherwise:
h = {foo:0,bar:1,baz:2}h.select! {|key,value|value<2 }# => {foo: 0, bar: 1}h.select! {|key,value|value<2 }# => nil
With no block given, returns a newEnumerator.
Related: seeMethods for Deleting.
Source
static VALUErb_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 and returns the first entry ofself as a 2-element array; seeEntry Order:
h = {foo:0,bar:1,baz:2}h.shift# => [:foo, 0]h# => {bar: 1, baz: 2}
Returnsnil ifself is empty.
Related: seeMethods for Deleting.
Source
VALUErb_hash_size(VALUE hash){ return INT2FIX(RHASH_SIZE(hash));}Returns the count of entries inself:
{foo:0,bar:1,baz:2}.size# => 3Related: seeMethods for Querying.
Source
static VALUErb_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 containing the entries fromself for the givenkeys; ignores any keys that are not found:
h = {foo:0,bar:1,baz:2}h.slice(:baz,:foo,:nosuch)# => {baz: 2, foo: 0}
Related: seeMethods for Deleting.
Source
static VALUErb_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 all elements ofself as an array of 2-element arrays; each nested array contains a key-value pair fromself:
h = {foo:0,bar:1,baz:2}h.to_a# => [[:foo, 0], [:bar, 1], [:baz, 2]]
Related: seeMethods for Converting.
Source
static VALUErb_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;}With a block given, returns a new hash whose content is based on the block; the block is called with each entry’s key and value; the block should return a 2-element array containing the key and value to be included in the returned array:
h = {foo:0,bar:1,baz:2}h.to_h {|key,value| [value,key] }# => {0 => :foo, 1 => :bar, 2 => :baz}
With no block given, returnsself ifself is an instance ofHash; ifself is a subclass ofHash, returns a new hash containing the content ofself.
Related: seeMethods for Converting.
Source
static VALUErb_hash_to_hash(VALUE hash){ return hash;}Returnsself.
Related: seeMethods for Converting.
Source
static VALUErb_hash_to_proc(VALUE hash){ return rb_func_lambda_new(hash_proc_call, hash, 1, 1);}Returns aProc object that maps a key to its value:
h = {foo:0,bar:1,baz:2}proc =h.to_procproc.class# => Procproc.call(:foo)# => 0proc.call(:bar)# => 1proc.call(:nosuch)# => nil
Related: seeMethods for Converting.
Source
static VALUErb_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;}With an argument, a block, or both given, derives a new hashnew_hash fromself, the argument, and/or the block; all, some, or none of its keys may be different from those inself.
With a block given and no argument,new_hash has keys determined only by the block.
For each key/value pairold_key/value inself, calls the block withold_key; the block’s return value becomesnew_key; setsnew_hash[new_key] = value; a duplicate key overwrites:
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}
With argumentother_hash given and no block,new_hash may have new keys provided byother_hash and unchanged keys provided byself.
For each key/value pairold_key/old_value inself, looks for keyold_key inother_hash:
If
old_keyis found, its valueother_hash[old_key]is taken asnew_key; setsnew_hash[new_key] = value; a duplicate key overwrites: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}
If
old_keyis not found, setsnew_hash[old_key] = value; a duplicate key overwrites: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}
Unused keys inother_hash are ignored:
h = {foo:0,bar:1,baz:2}h.transform_keys(bat:3)# => {foo: 0, bar: 1, baz: 2}
With both argumentother_hash and a block given,new_hash has new keys specified byother_hash or by the block, and unchanged keys provided byself.
For each pairold_key andvalue inself:
If
other_hashhas keyold_key(with valuenew_key), does not call the block for that key; setsnew_hash[new_key] = value; a duplicate key overwrites: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}
If
other_hashdoes not have keyold_key, calls the block withold_keyand takes its return value asnew_key; setsnew_hash[new_key] = value; a duplicate key overwrites: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}
With no argument and no block given, returns a newEnumerator.
Related: seeMethods for Transforming Keys and Values.
Source
static VALUErb_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;}With an argument, a block, or both given, derives keys from the argument, the block, andself; all, some, or none of the keys inself may be changed.
With a block given and no argument, derives keys only from the block; all, some, or none of the keys inself may be changed.
For each key/value pairold_key/value inself, calls the block withold_key; the block’s return value becomesnew_key; removes the entry forold_key:self.delete(old_key); setsself[new_key] = value; a duplicate key overwrites:
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}
With argumentother_hash given and no block, derives keys forself fromother_hash andself; all, some, or none of the keys inself may be changed.
For each key/value pairold_key/old_value inself, looks for keyold_key inother_hash:
If
old_keyis found, takes valueother_hash[old_key]asnew_key; removes the entry forold_key:self.delete(old_key); setsself[new_key] = value; a duplicate key overwrites: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}
If
old_keyis not found, does nothing: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}
Unused keys inother_hash are ignored:
h = {foo:0,bar:1,baz:2}h.transform_keys!(bat:3)# => {foo: 0, bar: 1, baz: 2}
With both argumentother_hash and a block given, derives keys fromother_hash, the block, andself; all, some, or none of the keys inself may be changed.
For each pairold_key andvalue inself:
If
other_hashhas keyold_key(with valuenew_key), does not call the block for that key; removes the entry forold_key:self.delete(old_key); setsself[new_key] = value; a duplicate key overwrites: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}
If
other_hashdoes not have keyold_key, calls the block withold_keyand takes its return value asnew_key; removes the entry forold_key:self.delete(old_key); setsself[new_key] = value; a duplicate key overwrites: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}
With no argument and no block given, returns a newEnumerator.
Related: seeMethods for Transforming Keys and Values.
Source
static VALUErb_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;}With a block given, returns a new hashnew_hash; for each pairkey/value inself, calls the block withvalue and captures its return asnew_value; adds tonew_hash the entrykey/new_value:
h = {foo:0,bar:1,baz:2}h1 =h.transform_values {|value|value*100}h1# => {foo: 0, bar: 100, baz: 200}
With no block given, returns a newEnumerator.
Related: seeMethods for Transforming Keys and Values.
Source
static VALUErb_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;}With a block given, changes the values ofself as determined by the block; returnsself.
For each entrykey/old_value inself, calls the block withold_value, captures its return value asnew_value, and setsself[key] = new_value:
h = {foo:0,bar:1,baz:2}h.transform_values! {|value|value*100}# => {foo: 0, bar: 100, baz: 200}
With no block given, returns a newEnumerator.
Related: seeMethods for Transforming Keys and Values.
Source
static VALUErb_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);}Updates values and/or adds entries toself; returnsself.
Each argumentother_hash inother_hashes must be a hash.
With no block given, for each successive entrykey/new_value in each successiveother_hash:
If
keyis inself, setsself[key] = new_value, whose position is unchanged:h0 = {foo:0,bar:1,baz:2}h1 = {bar:3,foo:-1}h0.update(h1)# => {foo: -1, bar: 3, baz: 2}
If
keyis not inself, adds the entry at the end ofself:h = {foo:0,bar:1,baz:2}h.update({bam:3,bah:4})# => {foo: 0, bar: 1, baz: 2, bam: 3, bah: 4}
With a block given, for each successive entrykey/new_value in each successiveother_hash:
If
keyis inself, fetchesold_valuefromself[key], calls the block withkey,old_value, andnew_value, and setsself[key] = new_value, whose position is unchanged :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}
If
keyis not inself, adds the entry at the end ofself:h = {foo:0,bar:1,baz:2}h.update({bat:3}) {fail'Cannot happen' }# => {foo: 0, bar: 1, baz: 2, bat: 3}
Related: seeMethods for Assigning.
Source
VALUErb_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 inself:
h = {foo:0,bar:1,baz:2}h.values# => [0, 1, 2]
Related: seeMethods for Fetching.
Source
static VALUErb_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 givenkeys:
h = {foo:0,bar:1,baz:2}h.values_at(:baz,:foo)# => [2, 0]
Thehash default is returned for each key that is not found:
h.values_at(:hello,:foo)# => [nil, 0]
Related: seeMethods for Fetching.