Use argument ruby as a hash key - ruby

I want to create a code to name organic chemestry compounds. How can I use the arguments (num, bond) as keys for the hash? Ignore what I did to global variables, it's just to have a general idea of what I intent to do.
class Molecule
def molecule_name(num, bond)
#num = { 1 => 'met', 2 => 'et', 3=> 'prop', 4 => 'but'}
#bond = {1 => 'ano', 2 => 'eno', 3 => 'ino'}
end
a = Molecule.new; a = a.molecule_name(2,1)
print a
end

The question is a little unclear, but I think this is roughly what you're trying to achieve:
class Molecule
def initialize(num, bond)
#num = num
#bond = bond
end
NAMES = {1 => 'met', 2 => 'et', 3 => 'prop', 4 => 'but'}
BONDS = {1 => 'ano', 2 => 'eno', 3 => 'ino'}
def molecule_name
[ NAMES[#num], BONDS[#bond] ]
end
end
a = Molecule.new(2, 1)
a.molecule_name # => ["et", "ano"]

I tried to modify as little as possible and still get a working example :
class Molecule
attr_reader :num, :bond
def to_s
"#{#num}, #{#bond}"
end
def molecule_name(num, bond)
#num = { 1 => 'met', 2 => 'et', 3=> 'prop', 4 => 'but'}[num]
#bond = {1 => 'ano', 2 => 'eno', 3 => 'ino'}[bond]
end
end
a = Molecule.new
a.molecule_name(2,1)
puts a
#=> et, ano
puts a.num
#=>et
puts a.bond
#=>ano
This example would be a bit more Ruby-ish :
class Molecule
attr_reader :num, :bond
##nums = { 1 => 'met', 2 => 'et', 3=> 'prop', 4 => 'but'}
##bonds = {1 => 'ano', 2 => 'eno', 3 => 'ino'}
def initialize(num_id, bond_id)
#num = ##nums[num_id]
#bond = ##bonds[bond_id]
end
def name
"#{num}, #{bond}"
end
end
a = Molecule.new(2,1)
puts a.name

Related

to_json introduces strange character

With this code I implemented a tree
groups = {"al1o0"=>"A1", "al2o2"=>"A10", "al2o3"=>"A11", "al1o1"=>"A2"}
map = {}
arr = []
groups.each_with_index do |group, index|
level = (group.first.split("o")[0].split("al")[1]).to_i - 1
level = level == 0 ? nil : level
order = group.first.split("o")[1]
arr.append({ :id=> index + 1, :order => order, :name => group.last, :parent => level})
end
root = {:id => 0, :name => '', :order => 0, :parent => nil}
arr.each do |e|
map[e[:id]] = e
end
tree = {}
arr.each do |e|
pid = e[:parent]
if pid == nil
(tree[root] ||= []) << e
else
(tree[map[pid]] ||= []) << e
end
end
tree has
=> {{:id=>0, :name=>"", :order=>0, :parent=>nil}=>[{:id=>1, :order=>"0", :name=>"A1", :parent=>nil}, {:id=>4, :order=>"1", :name=>"A2", :parent=>nil}], {:id=>1, :order=>"0", :name=>"A1", :parent=>nil}=>[{:id=>2, :order=>"2", :name=>"A10", :parent=>1}, {:id=>3, :order=>"3", :name=>"A11", :parent=>1}]}
Up to here all right but If I do tree.to_json, the output is
=> "{\"{:id=\\u003e0, :name=\\u003e\\\"\\\", :order=\\u003e0, :parent=\\u003enil}\":[{\"id\":1,\"order\":\"0\",\"name\":\"A1\",\"parent\":null},{\"id\":4,\"order\":\"1\",\"name\":\"A2\",\"parent\":null}],\"{:id=\\u003e1, :order=\\u003e\\\"0\\\", :name=\\u003e\\\"A1\\\", :parent=\\u003enil}\":[{\"id\":2,\"order\":\"2\",\"name\":\"A10\",\"parent\":1},{\"id\":3,\"order\":\"3\",\"name\":\"A11\",\"parent\":1}]}"
Why It changed :id=>0 in :id=\u003e0?
First of all tree looks weird.
{{:id=>0, :name=>"", :order=>0, :parent=>nil}=>[{:id=>1, :order=>"0", :name=>"A1", :parent=>nil}, ...]}}
here is a key
{:id=>0, :name=>"", :order=>0, :parent=>nil}
and
[{:id=>1, :order=>"0", :name=>"A1", :parent=>nil}, ...]
is a value.
Key should not be a hash. How to call it later then.
You might need something like
{"A1" => {name: 'foo', order: '0' }, 'A2' => ...}

I want to know what is wrong with my method to_s? Why am I still getting undefined method length if that method is created right above?

This is my code and my error message from my terminal. My project is trying to print out the months of a year like the Cal in the terminal.
class Month
attr_reader :month, :year
def initialize( month, year)
#month = month
#year = year
end
def month_names
names_of_months = {1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August', 9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December'}
return names_of_months[#month]
end
def length
days_of_months = {1 => '31', 2 => '28', 3 => '31', 4 => '30', 5 => '31', 6 => '30', 7 => '31', 8 => '31', 9 => '30', 10 => '31', 11 => '30', 12 => '31'}
return days_of_months[#month]
end
def to_s
output = "#{month_names} #{year} #{length}"
(1.length).each do |day|
output << day.to_s
end
output
end
end
and error message:
Error:
TestMonth#test_to_s_on_march_2015:
NoMethodError: undefined method `length' for 1:Fixnum
/Users/brandonespinoza/Desktop/code/RUBY/cal-app/lib/month.rb:22:in `to_s'
test/test_month.rb:56:in `test_to_s_on_march_2015'
You're calling .length on 1, which looks for the method .length on the Fixnum class. To use your length method, try replacing 1.length with just length.

ruby hash keys compare_by_identity

I have the following:
h1 = {}
h1.compare_by_identity
h1['a'] = '1'
h1['a'] = '2'
h1['a'] = '3'
a_key = h1.keys.first
p h1[a_key]
And it prints 1, how do I make it return 2 or 3?
how do I make it return 2 or 3?
h1[h1.keys[0]] # => "1"
h1[h1.keys[1]] # => "2"
h1[h1.keys[2]] # => "3"
You can of course access the list of values directly, but I don't think this is in the spirit of your question:
h1.values # => ["1", "2", "3"]
that's because 'a' it's a different object each time.
'a'.object_id == 'a'.object_id
=> false
a = 'a'
a.object_id == a.object_id
=> true
You can try using the same object/instance, or a Symbol.
h1 = {}
h1.compare_by_identity
h1['a'] = 1
puts h1['a'] # => nil
a = 'a'
h1[a] = 2
puts h1[a] # => 2
h1[:a] = 3
puts h1[:a] # => 3

How to change format of nested hashes

I'm looking for a solution how to write the format function which will take a string or nested hash as an argument and return the flatten version of it with the path as a key.
arg = "foo"
format(arg) # => { "hash[keys]" => "foo" }
arg = {:a => "foo", :b => { :c => "bar", :d => "baz" }}
format(arg) # => { "hash[keys][a]" => "foo", "hash[keys][b][c]" => "bar", "hash[keys][b][d]" => "baz" }
def hash_flatten h
h.inject({}) do |a,(k,v)|
if v.is_a?(Hash)
hash_flatten(v).each do |sk, sv|
a[[k]+sk] = sv
end
else
k = k ? [k] : []
a[k] = v
end
a
end
end
def format h
if h.is_a?(Hash)
a = hash_flatten(h).map do |k,v|
key = k.map{|e| "[#{e}]"}.join
"\"event[actor]#{key}\" => \"#{v}\""
end.join(', ')
else
format({nil => h})
end
end
arg = "sth"
puts format(arg)
# => "event[actor]" => "sth"
arg = {:a => "sth", :b => { :c => "sth else", :d => "trololo" }}
puts format(arg)
# => "event[actor][a]" => "sth", "event[actor][b][c]" => "sth else", "event[actor][b][d]" => "trololo"

How do I replace all the values in a hash with a new value?

Let's say I have an arbitrarily deep nested Hash h:
h = {
:foo => { :bar => 1 },
:baz => 10,
:quux => { :swozz => {:muux => 1000}, :grimel => 200 }
# ...
}
And let's say I have a class C defined as:
class C
attr_accessor :dict
end
How do I replace all nested values in h so that they are now C instances with the dict attribute set to that value? For instance, in the above example, I'd expect to have something like:
h = {
:foo => <C #dict={:bar => 1}>,
:baz => 10,
:quux => <C #dict={:swozz => <C #dict={:muux => 1000}>, :grimel => 200}>
# ...
}
where <C #dict = ...> represents a C instance with #dict = .... (Note that as soon as you reach a value which isn't nested, you stop wrapping it in C instances.)
def convert_hash(h)
h.keys.each do |k|
if h[k].is_a? Hash
c = C.new
c.dict = convert_hash(h[k])
h[k] = c
end
end
h
end
If we override inspect in C to give a more friendly output like so:
def inspect
"<C #dict=#{dict.inspect}>"
end
and then run with your example h this gives:
puts convert_hash(h).inspect
{:baz=>10, :quux=><C #dict={:grimel=>200,
:swozz=><C #dict={:muux=>1000}>}>, :foo=><C #dict={:bar=>1}>}
Also, if you add an initialize method to C for setting dict:
def initialize(d=nil)
self.dict = d
end
then you can reduce the 3 lines in the middle of convert_hash to just h[k] = C.new(convert_hash_h[k])
class C
attr_accessor :dict
def initialize(dict)
self.dict = dict
end
end
class Object
def convert_to_dict
C.new(self)
end
end
class Hash
def convert_to_dict
Hash[map {|k, v| [k, v.convert_to_dict] }]
end
end
p h.convert_to_dict
# => {
# => :foo => {
# => :bar => #<C:0x13adc18 #dict=1>
# => },
# => :baz => #<C:0x13adba0 #dict=10>,
# => :quux => {
# => :swozz => {
# => :muux => #<C:0x13adac8 #dict=1000>
# => },
# => :grimel => #<C:0x13ada50 #dict=200>
# => }
# => }

Resources