Access symbol key of array of one hash value? - ruby

Is there a better, faster, and more direct way to access the symbol key of :a2 in this array of one hash [{:a2=>nil}]?
I have tried #new_array.first.first.first and #new_array.first.keys.first.

I would use #new_array.first.keys.first, but this is assuming you always want the first key of the first hash.

Related

How does looking up into a hash work in Ruby?

How does Ruby look for keys in a hash? I thought that as soon as it finds a key inside a hash, it returns its value without evaluating the other key/value pairs? But I guess I am wrong.
Eg,
test = {"a" => 10, "b" => 20, "c" => 30, "d" => 1/0}
now if i do test["a"], it returns error because of d's infinite value, if i remove "d", it works fine(which means it checks all the key/value pairs even if it finds a match in the first key). So if i search for a key in a really large hash, does Ruby evaluate every key/value for validity before returning the value for that particular hash? If that is the case, is there a way to break out of the hash as soon as it finds the key?
UPDATE
Just to clarify, I am trying to understand how it works in Ruby. So, for eg, if i have a hash with 500 key/value pairs(all valid not like 1/0), and lets say "a" is the first key. So if i do test["a"] on that large hash, does Ruby load all the key/value pairs in memory under the hood or just break out after it finds the key "a"?
The error you are getting occurs when ruby is creating the hash, not while accessing it - inserting the values into the hash clearly requires evaluating them.
There is no "loading" going on when fetching a value from a hash: the entirety of the hash is always in memory. A full explanation of hash tables is a bit out of scope but in a nutshell a hash works by hashing the key from which ruby derives which of the hashes buckets should contain the value. That bucket is then searched and the value is returned if the key is found.

How to add a value to an existing hash without a key

I need to assign the numbers 0-100000 to a hash without giving a key.
Ruby uses Murmur as hash function. How can I add a value without having a key, like in C, letting it handle collision and other things. Is it possible? Can I give just the value to hash and let it evaluate the key, then insert to itself?
In a normal hashing operation, we have a hash function, and a table. We use value as the argument of the hash function, then we get a key in return. The value is inserted to the key location in the table (if a collision happens, double hashing or something else used).
Is it possible to do the same type of hashing in Ruby? Or am I stuck with default ways? Can I just throw the value into a function, then it evaluates the key, and inserts the value to the hash table or not?
Just store into the hash using the calculated hash of the key, rather than the key itself:
hash[hash_func(key)] = value
That is, instead of mapping key -> value directly, this maps hash_func(key) -> value. The implementation may pass your hashed key value through another hash function internally, but you needn't care about that.
However, in comments it now comes to light that you want to apply the hash function to the value, not any other key. In that case, just use a set and be done with it. Then, all you need to do is add values to the set:
s = Set.new
s.add(value)
There's no need to calculate the hash of anything; Set will take care of it for you.
In short, this seems to be a case of the XY Problem. You needed to store a set of values in a data structure (and presumably be able to check if those values were stored in an efficient manner). Instead of asking about this, you asked about hash functions and tables. If you had asked about what you really needed, instead of asking about something else that you thought you could use to solve the original problem, you would have had a useful answer much more quickly.
The common solution is to simply use the value as a key. Hence:
value = "xxx"
hash[value] = 1
This way, you clearly document that the actual values (all 1) of this particular hash are of no use, and you will get de-duplicated values. Hash will do the usual hashing internally, you don't need to worry about it at all.
I use 1 as value here, but the actual value is completely irrelevant. I don't use nil as that is the default return value of hash[nonexistant_value].
If your values are more complex, check out http://docs.ruby-lang.org/en/2.0.0/Hash.html for specifics about them.

Updating Hash Values in Ruby Clarified

I was going to comment on the original question but I don't have the reputation to do so yet....
I too was wondering how to easily update all the values in a hash, or if there was some kind of equivalent .map! method for hashes. Someone put up this elegant solution:
hash.update(hash){|key,v1| expresion}
on this question:
Ruby: What is the easiest method to update Hash values?
My questions is how does the block know to iterate over each element in the hash? For example, I'd have to call .each on a hash to access each element normally so why isn't it something like:
hash.update(hash.each) do |key ,value|
value+=1
end
In the block with {|key, value| expression} I am accessing each individual hash element yet I don't have to explicitly tell the system this? Why not? Thank you very much.
Hash#update is an alias for Hash#merge! which is more descriptive.
When calling the method with a block, the following happens (excerpt from the docs):
If [a] block is specified, [...] the value of each duplicate key is
determined by calling the block with the key [...]
So, the above code works like this:
The hash is merged with itself, and for each duplicate key the block is called. As we merge the hash with itself, every newly added key is a duplicate and therefore the block is invoked. The result is that every value in the hash gets replaced by expresion.
Hash#update takes a hash as the first parameter, and an optional block as the second parameter. If the second parameter is left out, the method will internally loop on each key-value pair in the supplied hash and use them to merge into the original hash.
If the block (second parameter) is supplied, the method does exactly the same thing. It loops over each key-value in the supplied hash and merges it in. The only difference is where a collision is found (the original hash already has an entry for a specific key). In this case the block is called to help resolve the conflict.
Based on this understanding, simply passing the hash into itself will cause it to loop over every key-value because that's how update always works. Calling .each would be redundant.
To see this more clearly, take a look at the source code for the #update method, and note the internal call to rb_hash_foreach in either logic branch.

Maximum arity of ruby function?

I am looking to make an efficient function to clear out a redis-based cache.
I have a method call that returns a number of keys from redis:
$redis.keys("foo:*")
That returns all the keys that start with "foo:". Next, I'd like to delete all the values for these keys.
One (memory-intensive) way to do this is:
$redis.keys("foo:*").each do |key|
$redis.del(key)
end
I'd like to avoid loading all the keys into memory, and then making numerous requests to the redis server.
Another way that I like is to use the splat operator:
keys = $redis.keys("foo:*")
$redis.del(*keys)
The problem is that I don't know what the maximum arity of the $redis.del method, nor of any ruby method, I can't seem to find it online.
What is the maximum arity?
#muistooshort in the comments had a good suggestion that turned out to be right, the redis driver knows what to do with an array argument:
# there are 1,000,000 keys of the form "foo:#{number}"
keys = $redis.keys("foo:*")
$redis.del(keys) # => 1000000
Simply pass an array of keys to $redis.del

ruby object.hash

What's the meaning of an object's hash value? And in which case does two object has the same hash value?? Also it is said that Array|Hash can't be Hash keys, this has something to do with object's hash value, why?
For objects to be stored in hashmaps or hashsets the following must hold true:
If two objects are considered equal, their hash value must also be equal.
If two objects are not considered equal, their hash value should be likely to be different (the more often two different objects have the same hash value, the worse the performance of operations on the hashmap/set).
So if two objects have the same hash value there is a good chance (but no guarantee) that they are equal.
What exactly "equal" means in the above is up to the implementor of the hash method. However you should always implement eql? to use the same definition of equality as hash.
For classes that don't override hash (i.e. classes using Object's hash implementation) hash equality is defined in terms of object identity. I.e. two objects are considered equal if and only if the reside at the same location in memory.
In ruby up to 1.8.6 Array and Hash did not override hash. So if you used arrays (or hashes) as hash keys, you could only retrieve the value for a key, if you used the exact same array as a key for retrieval (not an array with the same contents).
In ruby 1.8.7+ Array#hash and Hash#hash (as well as their eql? methods) are defined so that they are equal when their elements are equal.
A hash value has no inherent meaning, but it is a way of representing that object such that it can be differentiated from other objects of the same type. When you create an object, it needs to implement hash such that if two objects have the same hash value, they will also be equal. What it means for two objects to be equal depends on the object; if you define, say, a Person object, you might want to say that two instances of Person are equal if they have the same name, id number, and birthdate. Or whatever criteria you choose.
Using an array or a hash as a hash key will now work since both do implement hash (such that the hash value is based on their contents). However, you can run into trouble when using a modifiable object such as an array as a key if there's any chance you might modify it. For example, if you have a variable of type Array, and you use it as a key to put something into a hash, and then you add something to the array, and try to use that variable as the key to get the something back out of the hash, it won't work (as the array's hash value has changed). The solution to this issue is to call Rehash on your hash after you modify the array.
What you're looking for is the concept of hashing.
It's not just for objects, is a broader concept.
Let's start with basics:
There are 3 things to be considered before understanding Object.hash.
memory address = Address of an Object in RAM.
value = value of an Object.
Type = Type of an Object.
Now let's understand different Object comparison operators.
"eql?" checks if the value of two operands are equal.
"==" checks if the value and type of two operands are the same.
"equal?" checks is this the exact same object?
Example 1: If address of two Object is same then they are pointing to same memory location whose value and Type is same as well.
a="5"
b=a
a.object_id => 194639
b.object_id => 194639
a.eql?(b) => true
a==b => true
a.equal?(b) => true
Example 2: Below example demonstrates hash of string and integer "5" is different.
> "5".eql?(5) => false
> 5.eql?(5) => true
> "5".eql?("5") => true
> 5.hash => -3271834327245180286
> "5".hash => -3126022673147098896
Conclusion:
If value and type of object is same then it will have same hash.

Resources