Initializing Hashes

Initializing hashes

There are two ways to create initial values with for a Hash.

One is to pass a single object in to Hash.new. This works well in many situations, especially if the object is a frozen value, but if the object has internal state, this may have unexpected side-effects. Since the same object is shared between all keys without an assigned value, modifying the internal state for one will show up in all.

a_hash = Hash.new "initial value"
a_hash['a'] #=> "initial value"
# op= methods don't modify internal state (usually), since they assign a new
# value for the key.
a_hash['b'] += ' owned by b' #=> "initial value owned by b"
# other methods, like #<< and #gsub modify the state of the string
a_hash['c'].gsub!(/initial/, "c's")
a_hash['d'] << " modified by d"
a_hash['e'] #=> "c's value modified by d"

Another initialization method is to pass Hash.new a block, which is invoked each time a value is requested for a key that has no value. This allows you to use a distinct value for each key.

another_hash = Hash.new { "new initial value" }
another_hash['a'] #=> "new initial value"
# op= methods still work as expected
another_hash['b'] += ' owned by b'
# however, if you don't assign the modified value, it's lost,
# since the hash rechecks the block every time an unassigned key's value is asked for
another_hash['c'] << " owned by c" #=> "new initial value owned by c"
another_hash['c'] #=> "new initial value"

The block is passed two arguments: the hash being asked for a value, and the key used. This gives you the option of assigning a value for that key, so that the same object will be presented each time a particular key is given.

yet_another_hash = Hash.new { |hash, key| hash[key] = "#{key}'s initial value" }
yet_another_hash['a'] #=> "a's initial value"
yet_another_hash['b'] #=> "b's initial value"
yet_another_hash['c'].gsub!('initial', 'awesome')
yet_another_hash['c'] #=> "c's awesome value"
yet_another_hash #=> { "a" => "a's initial value", "b" => "b's initial value", "c" => "c's awesome value" }

This last method is the one I most often use. It's also useful for caching the result of an expensive calculation.

how to initializing a hash table in C

What you are dealing with is Undefined Behavior.

See, struct node_t *hash_table[HSZ];
So, hash_table is an array of HSZ (127) pointers of the data type struct node_t.

When you do,

for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}

hash_table[0] to hash_table[126] pointers are not pointing to anything.
So, each of them (or all of them) should be initialized first to point to an object of the type struct node_t and then you can initialize them. For that matter, Using a memset does not cause a problem because memset is filling the contents of the pointers with all zeros. There is difference between filling the pointers with all zeros and filling all zeros to the memory pointed by pointers.

Trying this,

for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}

is plain wrong.

To fix the issue you are facing, you need to allocate memory dynamically using malloc. You can do the in your for loop.

for(i = 0; i < HSZ; i++) 
{
//Allocate memory of the size struct_node_t
hash_table[i] = malloc(sizeof(struct node_t)); //Do not cast!
//Check if memory is allocated
if(hash_table[i] == NULL)
{
//Memory not allocated, set some error state to handle and break
break;
}
//Initialize to zero
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}

Initializing a Hash with empty array unexpected behaviour

Just do

a = Hash.new { |h, k| h[k] = [] }
a[1] << "asd"
a # => {1=>["asd"]}

Read the below lines from the Hash::new documentation. It really explains why you didn't get the desired result.

new(obj) → new_hash

If obj is specified, this single object will be used for all default values.

new {|hash, key| block } → new_hash

If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required.

You can test by hand :

a = Hash.new([])
a[1].object_id # => 2160424560
a[2].object_id # => 2160424560

Now with the above style of Hash object creation, you can see every access to an unknown key, returning back the same default object. Now the other way, I meant block way :

b = Hash.new { |h, k| [] }
b[2].object_id # => 2168989980
b[1].object_id # => 2168933180

So, with the block form, every unknown key access, returning a new Array object.

How do I initialize values in a hash without a loop?

use strict;
use warnings; # Must-haves

# ... Initialize your arrays

my @fields = ('currency_symbol', 'currency_name');
my @array = ('BRL','Real');

# ... Assign to your hash

my %hash;
@hash{@fields} = @array;

What is the difference between initializing hash two times and clear?

According to the docs, if you see the source code for clear method, it iterates through each element in the hash and removes it.

When you do hash = {}, it will just create a new empty hash object but the old object will still be in memory ready for garbage collection if there are no other references for that object.



Related Topics



Leave a reply



Submit