Iterate hash for specific range - ruby

How to pass range in hash to iterate from index 1 to last?
h = {}
h[1..-1].each_pair do |key,value|
puts "#{key} = #{value}
end
This code returning error. how may i pass range in hash ??
EDIT:
I want to print first key and value without any calculations.
From second key and value i want to do some calculation on my hash.
For that i have written this code ...
store_content_in_hash containing key and values.
first_key_value = store_content_in_hash.shift
f.puts first_key_value[1]
f.puts
store_content_in_hash.each_pair do |key,value|
store_content_in_hash[key].sort.each {|v| f.puts v }
f.puts
end
Any better way to solve out this problem ??

In Ruby 1.9 only:
Given a hash:
h = { :a => :b, :c => :d, :e => :f }
Go Like this:
Hash[Array(h)[1..-1]].each_pair do |key, value|
# ...
end
This will iterate through the following hash { :c => :d, :e => f } as the first key/value pair is excluded by the range.

Hashes have no concept of order. There is no such thing as the first or second element in a hash.
So you can't do what you want with hashes.

Hash is not about the ranges. It's about key value pairs. In ruby 1.8 hash is unordered hence you can't be sure in which order the keys and values will be iterated over which makes "range" thing obsolete. And I believe that you're doing something wrong (tm) in this situation. Can you elaborate on your problem?
On the other note you're getting an error because square brackets in Hash instance accepts keys. So if your hash does not contain 1..-1 as a key - you will get nil value and nil does not respond to each_pair. Try this to get a hold on this:
h = {(1..-1) => {:foo => :bar}}
h[1..-1].each_pair do |key,value|
puts "#{key} = #{value}"
end

As others have pointed out, Hashes are not about order. It's true that 1.9 hashes are ordered, but that's just a convenience, not their primary feature.
If the order is important to you, just use arrays instead of hashes. In your case, an array of pairs (two-element arrays) seems to fit the purpose. And if you need to access it by key, you can always easily convert it to a hash using Hash#[] method.

Related

Ruby : Extract Key and Value from hash

I have an array of hashes that I'm having trouble with extracting the key and value. The array looks like:
data = [{"key"=>"Name", "value"=>"Jason"}, {"key"=>"Age", "value"=>"21"},
{"key"=>"last_name", "value"=>"bourne"}]
How can I convert this to the following array of hashes?
[{"Name"=>"Jason"}, {"Age"=>"21"}, {"last_name"=>"bourne"}]
I was able to use detect :
a = d.detect { |x| x["key"] == "Name" }
puts a['value']
to get the value for "name", but would like to know if there is a better way.
I'd say that the most elegant way to go about this is probably to convert data into a Hash first (assuming there are never any duplicate keys), like so:
data = data.map { |x| [x['key'], x['value']] }.to_h
# => {"Name"=>"Jason", "Age"=>"21", "last_name"=>"bourne"}
The #to_h method expects each element of the array to be an array in the form [key, value], so the #map call processes each element of data to convert it into that form.
Once this has been done, you can simply access keys like any other hash:
data['Name'] # => "Jason"
data['Age'] # => "21"
The calculation should not depend on the keys of the hashes, in case they are changed.
data.map { |h| [h.values].to_h }
#=> [{"Name"=>"Jason"}, {"Age"=>"21"}, {"last_name"=>"bourne"}]

How to sort a hash within a hash?

I'm trying to sort a hash within a hash. I'd like to sort the hash by the sub-key. I'm using ruby.
I've tried using the sort_by method and iterating the over the hash to reorganize the sub-key. I received the error "ArgumentError: comparison of Hash with Hash failed"
hash = {2012 => {"regularseason" => [game_1, game_2, game_3],
"post_season" => [game_4, game_5]
},
2013 => {"regularseason" => [game_6, game_7, game_8],
"post_season" => [game_9, game_10]
},
2014 => {"post_season" => [game_11, game_12, game_13],
"regularseason" => [game_14, game_15]
}
}
Desired Result:
I would like to sort this hash so sub-key post_season will always appear before sub-key regularseason.
Use Hash#transform_values to sort values:
hash.transform_values { |v| v.sort.to_h }
#⇒ {2012=>{"post_season"=>[:game_4, :game_5],
# "regularseason"=>[:game_1, :game_2, :game_3]},
# 2013=>{"post_season"=>[:game_9, :game_10],
# "regularseason"=>[:game_6, :game_7, :game_8]},
# 2014=>{"post_season"=>[:game_11, :game_12, :game_13],
# "regularseason"=>[:game_14, :game_15]}}
Hashes return keys in the order they are inserted so I believe you'll essentially need to rewrite the nested hash.
For example:
hash.each { |(key, nested_hash)| hash[key] = nested_hash.sort.to_h }
This is rather inefficient, however, so you'd be better to see if you can ensure they are always entered in that order or somehow extract them in the order you desire.
Given a hash with keys that include k, we can return a new hash with the same key/value pairs, with k being the first key inserted, and the remaining keys maintaining their original relative order, as follows:
def reorder_key(h, key)
{ key=>h[key] }.merge h
end
For example:
h = { 1=>2, :a=>:b, "c"=>"d" }
reorder_key(h, :a)
#=> {:a=>:b, 1=>2, "c"=>"d"}
We can use this method to obtain the desired hash in the present problem.
hash.transform_values { |h| reorder_key(h, "post_season") }
#=> {2012=>{"post_season" =>[:game_4, :game_5],
# "regularseason"=>[:game_1, :game_2, :game_3]},
# 2013=>{"post_season" =>[:game_9, :game_10],
# "regularseason"=>[:game_6, :game_7, :game_8]},
# 2014=>{"post_season" =>[:game_11, :game_12, :game_13],
# "regularseason"=>[:game_14, :game_15]}}
This approach does not depend on "post_season" coincidentally preceding "regularseason" lexicographically. If, for example, it were decided to add the key "spring_training" and make that the first key to appear for each year in the returned hash, it would only be necessary to change the value of the second argument of reorder_key to "spring_training".

compute hash value of same key ruby

I start with a basic hash where the key is a string and value an integer.
hash = {"a"=>2, "b"=>3}
Then what I try to achieve is that i want to push several times into that hash a new hash with different keys or / and same :
hash2 = {"c"=>4, "a"=>5}
The result should be
h_result = {"a"=>7, "b"=>3, "c"=>4}
The first thing would be to push the new hash and keep the duplicate keys.
I saw that answer = How can I merge two hashes without overwritten duplicate keys in Ruby? but it seems that it's not working..
Then I think I should match the same keys and compute the values. But again I can't find the answer.
Thanks guys
If you just want to compute equal keys in the hash what you are looking for is the merge method in the Hash class.
https://ruby-doc.org/core-2.2.1/Hash.html#method-i-merge
Returns a new hash containing the contents of other_hash and the
contents of hsh. If no block is specified, the value for entries with
duplicate keys will be that of other_hash. Otherwise the value for
each duplicate key is determined by calling the block with the key,
its value in hsh and its value in other_hash.
When you pass a block to the merge method it will yield both old value and new value, and the you can do your computation there.
For instance:
hash = {"a"=>2, "b"=>3}
hash2 = {"c"=>4, "a"=>5}
result = hash.merge(hash2) { |key, old_val, new_val| old_val + new_val }
p result #=> {"a"=>7, "b"=>3, "c"=>4}
Just use Hash#merge with a block and tell Ruby what to do when the key exists in both hashes – in this example just add the value from the second hash to the value from the first hash.
hash.merge(hash2) { |key, v1, v2| v1 + v2 }
#=> { "a" => 7, "b" => 3, "c" => 4 }

Array of paths from Nested Hash

I have a hash
my_hash = {"key1"=> {"key2"=> {"key3"=> "value"}}, "key4"=> "value"}
I want to return only the full path of the keys as an array. All concatenated like this
[key1, key1key2, key1key2key3, key4].
Any suggestions on how to do this. Thanks
I've been able to solve this with the iteraptor helpers suggested by this user. Thanks
I used the feature 'aplanar' i.e
hash.aplanar.keys
returns the paths of all the keys that have values. Just as I wanted.
The following is a recursive method that progressively modifies the keys of inner hashes. For example,
{"key2"=> {"key3"=> "value"}}
is changed to
{"key1key2"=> {"key3"=> "value"}}
after which
{"key3"=> "value"}
is changed to
{"key1key2key3"=> "value"}
This allows me to simply accumulate the keys of these hashes.
def recurse(h)
h.map do |k,v|
next k unless v.is_a?(Hash)
key, val = v.flatten
[k, recurse("#{k}#{key}"=>val)]
end.flatten
end
recurse my_hash
#=> ["key1", "key1key2", "key1key2key3", "key4"]

access hashes of hashes values in ruby

I have a nested hashes in ruby and I need to access a specific value of it. My hash look like below.
hash =
{"list"=>
{"0"=>
{"date"=>"11/03/2014",
"item1"=>"",
"tiem2"=>"News",
"item3"=>"",
"item4"=>"",
"item5"=>"Videos",
"Type"=>"Clip"},
"1"=>
{"date"=>"11/03/2014",
"item1"=>"",
"tiem2"=>"News",
"item3"=>"",
"item4"=>"",
"item5"=>"Videos",
"Type"=>"Program"}
}}
I need to access the value of "Type" of each keys.
I tried with the below code but I am not sure why it didn't work.
hash_type = hash["list"].keys.each {|key| puts key["Type"]}
But it returned the list of keys. i.e 0 and 1
Please help.
hash["list"].map {|_, hash| hash['Type']}
Explanation:
hash = {key: 'value'}
You can loop over a hash using each like this:
hash.each {|pair| puts pair.inspect } #=> [:key, 'value']
or like this
hash.each {|key, value| puts "#{key}: #{value}"} #=> key: value
Since we don't use key anywhere, some of the IDEs will complain about unused local variable key. To prevent this it is ruby convention to use _ for variable name and all the IDEs will not care for it to be unused.
hash['list'].collect { |_, value| value['Type'] }
=> ["Clip", "Program"]
This is following your logic (some answers posted different ways to do this). The reason why you go things wrong, if we go step by step is:
hash_type = hash["list"].keys #=> ["0", "1"]
So everything after that is the same like:
["0", "1"].each {|key| puts key["Type"]}
So you're basically doing puts '1'['Type'] and '0'['Type'] which both evaluate to nil (try it in IRB) . Try replacing the puts with p and you'll get nil printed 2 times. The reason why you're getting hash_type to be ["0", "1"] is because your last expression is keys.each and each ALWAYS return the "receiver", that is the array on which you called each (as we saw earlier, that array is ["0", "1"]).
The key to solving this, following your particular logic, is to put the "keys" (which are '0' and '1' in this instance) in the appropriate context, and putting them in a context would look something like this:
hash_type = hash["list"].keys.each {|key| puts hash["list"][key]["Type"]}`
This will print the keys. However, hash_type will still be ["0", "1"] (remember, each returns the value of the receiver). If you want the actual type values to be stored in hash_types, replace each with map and remove puts:
hash_type = hash["list"].keys.map {|key| hash["list"][key]["Type"]} #=> ["Clip", "Program"]

Resources