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
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' => ...}
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.
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
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"
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>
# => }
# => }