convert array to hash and initialize to a value - ruby

what is the best way to convert an array of
arr = ["one", "two", "three", "four", "five"]
to hash of
{"one"=>0, "two"=>0, "three"=>0, "four"=>0, "five"=>0}
Iam planning to fillup the '0' with my own values later, I just need the technique now.
Thanks.

arr.product([0]).to_h
or for versions < 2.0
Hash[arr.product([0])]

I don't know if it's the best way:
Hash[arr.map{ |el| [el, 0] }]

I would do this:
arr.inject({}) { |hash, key| hash.update(key => 0) }

Hash[ *arr.collect { |v| [ v, 0 ] }.flatten ]

You can also do
arr.each_with_object({}) {|v, h| h[v] = 1}
where:
v is the value of each element in the array,
h represents the hash object

Related

How to convert, in Ruby, a list of key value pairs to a Hash, such that values with duplicate keys are stored in an array?

Given a list key-value pairs, in the form of an array of arrays - e.g. [ ["key1","value1"], ["key2","value2"], ["key1", "value3"] ], how to convert these to a Hash that stores all the values, in the most elegant way?
For the above example, I would want to get { "key1" => [ "value1", "value3" ], "key2" => [ "value2" ] }.
[["key1","value1"], ["key2","value2"], ["key1", "value3"]]
.group_by(&:first).each{|_, v| v.map!(&:last)}
Another way is to use the form of Hash#update (aka merge!) that uses a block to determine the values of keys that are in both hashes being merged.
arr = [ ["key1","value1"], ["key2","value2"], ["key1", "value3"] ]
arr.each_with_object({}) { |(k,v),h| h.update(k=>[v]) { |_,o,n| o+n } }
#=> {"key1"=>["value1", "value3"], "key2"=>["value2"]}
Hash.new{ |h,k| h[k]=[] }.tap{ |h| array.each{ |k,v| h[k] << v } }
OR
c = Hash.new {|h,k| h[k] = [] }
array.each{|k, v| c[k] << v}
My best solution so far is this:
kvlist.inject(Hash.new([])) do |memo,a|
memo[a[0]] = (memo[a[0]] << a[1])
memo
end
Which I think is not very good.

ruby set key of hash for array of hashes

Given the following array of hashes, how can I make a new hash with friend_id as the key and dist the value?
results = [
{"user_id"=>"18", "friend_id"=>"17", "dist"=>"1"},
{"user_id"=>"18", "friend_id"=>"42", "dist"=>"1"},
{"user_id"=>"18", "friend_id"=>"43", "dist"=>"1"},
{"user_id"=>"18", "friend_id"=>"46", "dist"=>"2"}
]
desired_hash = {"17" => "1", "42" => "1", "43" => "1", "46" => "2"}
I've tried map but the values are then in an array. I also tried to flatten that result but it flattened the key instead of the value
results.each_with_object({}) { |g,h| h[g["friend_id"]] = g["dist"] }
or
results.each_with_object({}) { |g,h| h.update(g["friend_id"]=> g["dist"]) }
For this use case, I think it would be simpler and more readable to just use #each:
desired_hash = Hash.new
results.each {|h| desired_hash[h["friend_id"]] = h["dist"]}
Then, desired_hash is:
#=> {"17"=>"1", "42"=>"1", "43"=>"1", "46"=>"2"}
You can use Enumerable#inject method.
results.inject({}) {|sum, e| sum.merge({e["friend_id"] => e["dist"]})}
# => {"17"=>"1", "42"=>"1", "43"=>"1", "46"=>"2"}
results.map {|h| [h['friend_id'], h['dist']]} .to_h
Although I probably like #CarySwoveland 's answer better, on the lines of:
results.each_with_object({}) {|h, n| n[h['friend_id']] = h['dist']}
Simply:
desired_hash = Hash[results.map{ |h| [ h['friend_id'], h['dist']] }]
or as Victor suggests
desired_hash = Hash[results.map{ |x| x.values_at('friend_id', 'dist') }]

Add values of an array inside a hash

I created a hash that has an array as a value.
{
"0":[0,14,0,14],
"1":[0,14],
"2":[0,11,0,12],
"3":[0,11,0,12],
"4":[0,10,0,13,0,11],
"5":[0,10,0,14,0,0,0,11,12,0],
"6":[0,0,12],
"7":[],
"8":[0,14,0,12],
"9":[0,14,0,0,11,14],
"10":[0,11,0,12],
"11":[0,13,0,14]
}
I want the sum of all values in each array. I expect to have such output as:
{
"0":[24],
"1":[14],
"2":[23],
"3":[23],
"4":[34],
"5":[47],
"6":[12],
"7":[],
"8":[26],
"9":[39],
"10":[23],
"11":[27]
}
I do not know how to proceed from here. Any pointers are thankful.
I would do something like this:
hash = { "0" => [0,14,0,14], "1" => [0,14], "7" => [] }
hash.each { |k, v| hash[k] = Array(v.reduce(:+)) }
# => { "0" => [28], "1" => [14], "7" => [] }
For hash object you as this one.
hash = {"0"=>[0,14,0,14],"1"=>[0,14],"2"=>[0,11,0,12],"3"=>[0,11,0,12],"4"=>[0,10,0,13,0,11],"5"=>[0,10,0,14,0,0,0,11,12,0],"6"=>[0,0,12],"7"=>[],"8"=>[0,14,0,12],"9"=>[0,14,0,0,11,14],"10"=>[0,11,0,12],"11"=>[0,13,0,14]}
You could change value of each k => v pair
hash.each_pair do |k, v|
hash[k] = [v.reduce(0, :+)]
end
will resolve in
hash = {"0"=>[28], "1"=>[14], "2"=>[23], "3"=>[23], "4"=>[34], "5"=>[47], "6"=>[12], "7"=>[0], "8"=>[26], "9"=>[39], "10"=>[23], "11"=>[27]}
If your string is just like you mentioned you can parse it using JSON, or jump that step if you have already an Hash.
You can check the documentation of inject here
require 'json'
json_string = '
{
"0":[0,14,0,14],
"1":[0,14],
"2":[0,11,0,12],
"3":[0,11,0,12],
"4":[0,10,0,13,0,11],
"5":[0,10,0,14,0,0,0,11,12,0],
"6":[0,0,12],
"7":[],
"8":[0,14,0,12],
"9":[0,14,0,0,11,14],
"10":[0,11,0,12],
"11":[0,13,0,14]
}
'
hash = JSON.parse json_string
result = Hash.new
hash.each do |key, value|
result[key] = value.inject(:+)
end
puts result.inspect
and the result:
{"0"=>28, "1"=>14, "2"=>23, "3"=>23, "4"=>34, "5"=>47, "6"=>12, "7"=>nil, "8"=>26, "9"=>39, "10"=>23, "11"=>27}
Classic example for map/reduce. You need to iterate on the hash keys and values (map {|k,v|}), and for each value count the sum using reduce(0) {|acc, x| acc+x}
h = {1 => [1,2,3], 2 => [3,4,5], 7 => []} #example
a = h.map {|k,v| [k ,v.reduce(0) {|acc, x| acc+x}] }
=> [[1, 6], [2, 12], [7, 0]]
Hash[a]
=> {1=>6, 2=>12, 7=>0}

Convert an array to hash, where keys are the indices

I am transforming an array into a hash, where the keys are the indices and values are the elements at that index.
Here is how I have done it
# initial stuff
arr = ["one", "two", "three", "four", "five"]
x = {}
# iterate and build hash as needed
arr.each_with_index {|v, i| x[i] = v}
# result
>>> {0=>"one", 1=>"two", 2=>"three", 3=>"four", 4=>"five"}
Is there a better (in any sense of the word "better") way to do it?
arr = ["one", "two", "three", "four", "five"]
x = Hash[(0...arr.size).zip arr]
# => {0=>"one", 1=>"two", 2=>"three", 3=>"four", 4=>"five"}
Ruby < 2.1:
Hash[arr.map.with_index { |x, i| [i, x] }]
#=> {0=>"one", 1=>"two", 2=>"three", 3=>"four", 4=>"five"}
Ruby >= 2.1:
arr.map.with_index { |x, i| [i, x] }.to_h
x = Hash.new{|h, k| h[k] = arr[k]}
%w[one two three four five].map.with_index(1){ |*x| x.reverse }.to_h
Remove (1) if you want to start the index from 0.
Here is a solution making use of Object#tap, to add values to a newly-created hash:
arr = ["one", "two", "three", "four", "five"]
{}.tap do |hsh|
arr.each_with_index { |item, idx| hsh[idx] = item }
end
#=> {0=>"one", 1=>"two", 2=>"three", 3=>"four", 4=>"five"}
Many good solutions already, just adding a variant (provided you do not have duplicated values):
["one", "two", "three", "four", "five"].map.with_index.to_h.invert
# => {0=>"one", 1=>"two", 2=>"three", 3=>"four", 4=>"five"}
You could monkey patch Array to provide a new method:
class Array
def to_assoc offset = 0
# needs recent enough ruby version
map.with_index(offset).to_h.invert
end
end
Now you can do:
%w(one two three four).to_assoc(1)
# => {1=>"one", 2=>"two", 3=>"three", 4=>"four"}
This is a common operation I'm doing in Rails apps so I keep this monkey patch around in an initializer.
You should go with the map method, it's better and uses less memory. Another solution is with while loop. Good to know this way too, because often you may need to use the while loop.
At example 2, if you want to take each odd index in the an array as a key in the hash, and each even index as a value in the hash
Example 1:
some_array = ["one", "two", "three", "four", "five"]
def to_hash(arr)
counter = 0
new_hash = Hash.new(0)
while counter < arr.length
new_hash[counter] = arr[counter]
counter += 1
end
return new_hash
end
puts to_hash(arr)
# Output
{0=>"one", 1=>"two", 2=>"three", 3=>"four", 4=>"five"}
Example 2 -
Perhaps after getting data as a string, and you split this string to an array, and now you want to convert to key, value.
some_array = ['KBD', 'King Bedroom', 'QBD', 'Queen Bedroom', 'DBD', 'Double Bedroom', 'SGLB', 'Single Bedroom']
def to_hash(arr)
new_hash = Hash.new(0)
counter = 0
while counter < arr.length
new_hash[arr[counter]] = arr[counter+1]
counter += 2
end
return "#{new_hash}"
end
puts to_key_value_hash(some_array)
# Output
{"KBD"=>"King Bedroom", "QBD"=>"Queen Bedroom", "DBD"=>"Double Bedroom", "SGLB"=>"Single Bedroom"}
Many ways to do this, but just saying not to forget the while loop.

How to convert the values of a hash from String to Array in Ruby?

I'm looking to perform a conversion of the values in a Ruby hash from String to Integer.
I thought this would be fairly similar to the way you perform a conversion in a Ruby array (using the map method), but I have not been able to find an elegant solution that doesn't involve converting the hash to an array, flattening it, etc.
Is there a clean solution to do this?
Eg. From
x = { "a" => "1", "b" => "2", "c"=> "3" }
To
x = { "a" => 1, "b" => 2, "c" => 3 }
To avoid modifying the original Hash (unlike the existing answers), I'd use
newhash = x.reduce({}) do |h, (k, v)|
h[k] = v.to_i and h
end
If you're using Ruby 1.9, you can also use Enumerable#each_with_object to achieve the same effect a bit more cleanly.
newhash = x.each_with_object({}) do |(k, v), h|
h[k] = v.to_i
end
If you want to, you can also extract the logic into a module and extend the Hash class with it.
module HMap
def hmap
self.each_with_object({}) do |(k, v), h|
h[k] = yield(k, v)
end
end
end
class Hash
include HMap
end
Now you can use
newhash = x.hmap { |k, v| v.to_i } # => {"a"=>1, "b"=>2, "c"=>3}
My preferred solution:
Hash[x.map { |k, v| [k, v.to_i]}] #=> {"a"=>1, "b"=>2, "c"=>3}
A somewhat wasteful one (has to iterate over the values twice):
Hash[x.keys.zip(x.values.map(&:to_i))] #=> {"a"=>1, "b"=>2, "c"=>3}
Try this:
x.each{|k,v| x[k]=v.to_i}
p.keys.map { |key| p[key] = p[key].to_i }

Resources