Hash keys and values - ruby

I would like to know if you have any more practical way of working with keys, value in ruby.
I had to improvise to be able to access and print the keys Rafael and Roberto and at the same time print their keys and values
My code:
arr = Hash.new
arr["Rafael"] = []
arr["Roberto"] = []
listaProdutos = [
"banana",
"uva",
"biscoito"
]
listaProdutos.each{ |i|
arr["Rafael"] << {"Produto": i, "Quantidade": rand(1..9)}
arr["Roberto"] << {"Produto": i, "Quantidade": rand(1..9)}
}
arr.each{ |k,lista|
(0..arr.count).each do |i|
puts "#{k} vai comprar #{arr[k][i][:Quantidade]} unidades de #{arr[k][i][:Produto]}"
end
}

This:
arr.each{ |k,lista|
(0..arr.count).each do |i|
puts "#{k} vai comprar #{arr[k][i][:Quantidade]} unidades de #{arr[k][i][:Produto]}"
end
}
Can we rewritten as:
arr.each do |k, lista|
lista.each do |obj|
puts "#{k} vai comprar #{obj[:Quantidade]} unidades de #{obj[:Produto]}"
end
end

Related

How to refactor and reduce complexity

I have the following code:
#model = "ford"
#attribute = "name"
def grouped
grouped = {}
#array.each do |r|
field = r.car.send(#model)
if field.is_a? ActiveRecord::Associations::CollectionProxy
field.each do |obj|
key = obj.send(#attribute)
grouped[key] = [] unless grouped.has_key?(key)
grouped[key].push(r)
end
else
key = field.send(#attribute)
grouped[key] = [] unless grouped.has_key?(key)
grouped[key].push(r)
end
end
grouped
end
The result is:
{ford: [a, b, c]}
The codeclimate says that it has cognitive complexity.
How can I refactor this method to something cleaner?
def grouped
#array.each_with_object(Hash.new { |h, k| h[k] = [] }) do |r, grouped|
case field = r.car.send(#model)
when ActiveRecord::Associations::CollectionProxy
field.each do |obj|
grouped[obj.send(#attribute)] << r
end
else
grouped[field.send(#attribute)] << r
end
end
end

Using one Array to search a second array for frequency in ruby

I have an Array-1 say
arr1 =['s','a','sd','few','asdw','a','sdfeg']
And a second Array
arr2 = ['s','a','d','f','w']
I want to take arr1 and sort the frequency of letters by inputting arr2 with result
[s=> 4, a=> 2, d => 3] So on and so forth.
As far as I can muddle around.. Nothing below works, Just my thoughts on it?
hashy = Hash.new
print "give me a sentance "
sentance = gets.chomp.downcase.delete!(' ')
bing = sentance.split(//)
#how = sentance.gsub!(/[^a-z)]/, "") #Remove nil result
#chop = how.to_s.split(//).uniq
#hashy << bing.each{|e| how[e] }
#puts how.any? {|e| bing.count(e)}
#puts how, chop
bing.each {|v| hashy.store(v, hashy[v]+1 )}
puts bing
Thank you for your time.
I assumed that you want to count all letters in the sentence you put in, and not array 1. Assuming that, here's my take on it:
hashy = Hash.new()
['s','a','d','f','w'].each {|item| hashy[item.to_sym] = 0}
puts "give me a sentence"
sentence = gets.chomp.downcase.delete!(' ')
sentence_array = []
sentence.each_char do |l|
sentence_array.push(l)
end
hashy.each do |key, value|
puts "this is key: #{key} and value #{hashy[key]}"
sentence_array.each do |letter|
puts "letter: #{letter}"
if letter.to_sym == key
puts "letter #{letter} equals key #{key}"
value = value + 1
hashy[key] = value
puts "value is now #{value}"
end
end
end
puts hashy

how to push multiple values to same hash key

a beginner question here, please help me out
my_array = ["city1:state1","city2:state2","city3:state1","city4:state3","city5:state1"]
from this array how can i make a hash like this?
{
state1: [city1,city3,city5],
state2: [city2],
state3: [city4]
}
i am trying this way
my_hash = { }
my_array.each do |cs|
temp = cs.split(":")
if my_hash.keys.include? temp[1]
my_hash[temp[1]] = temp[0]
else
my_hash[temp[1]] = temp[0]
end
end
but i am not getting how to match keys of my hash and append to keys.
A little modification can work:
my_hash = { }
my_array.each do |cs|
temp = cs.split(":")
if my_hash.keys.include? temp[1].to_sym
my_hash[temp[1].to_sym] << temp[0]
else
my_hash[temp[1].to_sym] = [temp[0]]
end
end
Result is {:state1=>["city1", "city3", "city5"], :state2=>["city2"], :state3=>["city4"]}. I'm assuming this is what you mean (the keys are symbols, and the values are arrays of strings).
You can use Hash defaults to achieve an alternative solution:
my_array = ["city1:state1","city2:state2","city3:state1","city4:state3","city5:state1"]
hash = Hash.new do |hash, key|
hash[key] = []
end
my_array.each_with_object(hash) do |string, hash|
city, state = string.split(":")
hash[state.to_sym] << city
end
# => {:state1=>["city1", "city3", "city5"], :state2=>["city2"], :state3=>["city4"]}
Try this(considering that you mistyped state3:[city3] instead of state3:[city4] in your question):
my_array = ["city1:state1","city2:state2","city3:state1","city4:state3","city5:state1"]
my_hash = { }
my_array.each do |cs|
value, key = cs.split(":")
key = key.to_sym
if my_hash[key].present?
my_hash[key] << value
else
my_hash[key] = [value]
end
end
my_hash #=> {:state1=>["city1", "city3", "city5"], :state2=>["city2"], :state3=>["city4"]}
Or, one-liner:
my_hash = my_array.inject({}){|h, cs| value, key = cs.split(":"); key = key.to_sym; h[key].present? ? (h[key] << value) : h[key] = [value]; h }
my_hash #=> {:state1=>["city1", "city3", "city5"], :state2=>["city2"], :state3=>["city4"]}
or even better(based on jesper's idea of Hash):
my_array.inject(Hash.new{|h,k| h[k] = [] }){ |my_hash, cs| value, key = cs.split(":"); my_hash[key.to_sym] << value; my_hash }
my_hash #=> {:state1=>["city1", "city3", "city5"], :state2=>["city2"], :state3=>["city4"]}

Ruby hash of hash of hash

How can I have a hash of hash of hash?
My test returns
undefined method `[]' for nil:NilClass (NoMethodError)
Any tips?
found = Hash.new()
x = 1;
while x < 4 do
found[x] = Hash.new()
y = 1
while y < 4 do
found[x][y] = Hash.new()
found[x][y]['name1'] = 'abc1'
found[x][y]['name2'] = 'abc2'
found[x][y]['name3'] = 'abc3'
y += 1
end
x += 1
end
found.each do |k, v, y|
puts "k : #{k}"
puts " : #{v[y['name1']]}"
puts " : #{v[y['name2']]}"
puts " : #{v[y['name3']]}"
puts
end
I think you want something like this:
First of all create the data structure. You want nested hashes so you need to define default values for each hash key.
found = Hash.new do |hash,key|
hash[key] = Hash.new do |hash,key|
hash[key] = Hash.new
end
end
Run the search
(1..3).each do |x|
(1..3).each do |y|
found[x][y]['name1'] = 'abc1'
found[x][y]['name2'] = 'abc1'
found[x][y]['name3'] = 'abc1'
end
end
Then display the results
found.each do |x, y_hash|
y_hash.each do |y, name_hash|
name_hash.each do |name, value|
puts "#{x} => #{y} => #{name} => #{value}"
end
end
end
The way you build the hash seems to be functional. What probably causes the error is this loop:
found.each do |k, v, y|
Hash#each yields key/value pairs, so y will be assigned nil, thus causing the error two lines below. What you probably meant is a nested loop like
found.each do |x, h1|
h1.each do |y, h2|
puts h2['name1']
end
end
You should also be aware that you can write these kinds of counting loops more concisely in Ruby:
found = Hash.new { |h,k| h[k] = {} }
1.upto(3) do |x|
1.upto(3) do |y|
found[x][y] = {
'name1' => 'abc1',
'name2' => 'abc2',
'name3' => 'abc3',
}
end
end

separating key and multiple values for print with .each

I'm probably trying to be hard headed about this. I'm trying to format hash key and and array of values for output to user. Ruby-doc give me the code for it for one value. http://www.ruby-doc.org/core/classes/Hash.html#M002861
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
I'm trying to get
h = { "a" => [100,'green'], "b" => [200,'red'] }
h.each {|key, m,n| puts "#{key} is #{m} and #{n}"}
produces:
a is 100 and green
b is 200 and red
I've had some luck with
h.each{|key,m,n| puts "#{key} is #{[m,'n']} "}
it produces:
a is 100green
b is 200red
I need some space between my array of elements, how do I go about doing that?
h.each {|key, (m, n)| puts "#{key} is #{m} and #{n}"}
h.each { |key, value| puts "#{key} is #{value.first} and #{value.last}" }
I'm a fan of each_pair for hashes:
h.each_pair {|key, val| puts "#{key} is #{val[0]} and #{val[1]}" }
Or
h.each_pair {|key, val| puts "#{key} is #{val.join(' and ')}"}
h.each {|k,v| puts "#{k} is #{v[0]} and #{v[1]}"}

Resources