I would like to do smth like:
a = Hash.new
a = {:profile => #user}
a[:profile][:contacts] = Hash.new
a[:profile][:contacts] = #user.contacts.all
but I am getting the error can't write unknown attribute `contacts'.
#user is the result of a select from our database.
I need to create a hash with this structure
[:profile][:name] = boris
[:profile][:sex] = 1
[:propfile][:contacts] = here anotrher hash
The solution is convert to hash result after select from db using #user.as_json
a = Hash.new
a[:profile] = #user.as_json
a[:profile][:contacts] = #user.contacts.all
Related
I would like to iterate an array that has a database table names, I would like to create a hash like this:
{"table1"=>[column1,...,columnN],"table2"=>[column1,...,columnM]...}
This is what I did so far:
arr_table_names = ['table1','table2','table3']
arr_table_names.each do |table|
rs = pg_conn.exec 'SELECT * FROM table WHERE Id=0'
column_names = rs.nfields
h = Hash.new{|hsh,key| hsh[key] = [] }
h[table].push ??? column_names ?? I don't know how in this line
end
I tried to use Sebastian's solution, but got a syntax error:
def check_tables_same_content(table1,table2)
result = %w[#{table1} #{table2}].each_with_object([]) do |table, arr|
arr << { table.to_sym => #pg_conn.exec("SELECT * FROM #{table} WHERE false").fields }
end
puts result2
end
check_tables_same_content('company','company2')
company.rb:21:in `exec': ERROR: syntax error at or near "#" (PG::SyntaxError)
LINE 1: SELECT * FROM #{table1} WHERE false
^
Note that I am not looking on how to return column names.
Use .map to create a new array and pass the block. This should work:
arr_table_names.map do |table|
rs = pg_conn.execute "SELECT * FROM #{table} WHERE Id=0"
{table => rs.fields}
end
Update, you wanted a hash with the table names as keys, and columns as values so:
arr_table_names = ['table1','table2','table3']
hash = {}
arr_table_names.each do |table|
rs = pg_conn.execute "SELECT * FROM #{table} WHERE Id=0"
hash[table] = rs.fields
end
Update 2, you want the row data as an array for each column(key) in the hash:
arr_table_names = ['table1','table2','table3']
hash = {}
arr_table_names.each do |table|
rows = pg_conn.execute "SELECT * FROM #{table}"
hash[table] = rows.entries.map(&:values)
end
I have a list that contains hashes that looks similar to this:
list = [{"created_at"=>"2016-11-07T18:49:51.000Z",
"updated_at"=>"2016-11-07T18:49:51.000Z",
"id"=>1,
"name"=>"Test1",
"title"=>"Test1",
"description"=>""},
{"created_at"=>"2017-05-24T13:34:13.000Z",
"updated_at"=>"2017-05-24T13:34:13.000Z",
"id"=>23,
"name"=>"Test2",
"title"=>"Test2",
"description"=>nil}]
I want to be able to iterate over this list of hashes and create a new hash that only has the id's value as a key, and the name's value as the value of the key. Currently my solution is this:
def new_hash(list)
#new_hash = Hash.new
list.each do | x |
#new_hash[x["id"]] = x["name"]
end
end
This produces a hash like this:
{1=>"Test1", 23=>"Test2"}
My question is, is there a more elegant way to approach this in Ruby?
Try this one
Hash[list.map { |h| h.values_at('id', 'name') }]
=> {1=>"Test1", 23=>"Test2"}
list.each_with_object({}) { |g,h| h[g["id"]] = g["name"] }
Another option:
list.map {|hash| [hash["id"], hash["name"]]}.to_h
#=> {1=>"Test1", 23=>"Test2"}
data = {name: 'akshay', last_name: 'kakade'}
new_hash = Hash[data]
data.object_id
new_hash.object_id
I have some simple_hash:
old_hash = {"New"=>"0"}
I wan to convert it to new format:
new_hash = old_hash.keys.each do |key|
hash = Hash.new
hash[key] = {count: old_hash[key]}
hash
end
but this code returns me:
["New"]
instead of:
{"New"=>{:count=>"0"}}
And the question is why?
You are confusing the syntax of block with that of a method. In your code, new_hash gets the value of old_hash.keys, which is not what you want.
A little modification works:
new_hash = Hash.new
old_hash.keys.each do |key|
new_hash[key] = {count: old_hash[key]}
end
Do this:
hash = Hash.new
new_hash = old_hash.keys.each do |key|
hash[key] = {count: old_hash[key]}
hash
end
hash
# => {"New"=>{:count=>"0"}}
Since you placed hash = Hash.new inside the loop, you are creating a new hash every time.
So basically my code is as follows
anagrams = Hash.new([])
self.downcase.scan(/\b[a-z]+/i).each do |key|
anagrams[key.downcase.chars.sort] = #push key into array
end
so basically the hash would look like this
anagrams = { "abcdef" => ["fdebca", "edfcba"], "jklm" => ["jkl"]}
Basically what I don't understand is how to push "key" (which is obviously a string) as the value to "eyk"
I've been searching for awhile including documentation and other stackflow questions and this was my best guess
anagrams[key.downcase.chars.sort].push(key)
Your guess:
anagrams[key.downcase.chars.sort].push(key)
is right. The problem is your hash's default value:
anagrams = Hash.new([])
A default value doesn't automatically create an entry in the hash when you reference it, it just returns the value. That means that you can do this:
h = Hash.new([])
h[:k].push(6)
without changing h at all. The h[:k] gives you the default value ([]) but it doesn't add :k as a key. Also note that the same default value is used every time you try to access a key that isn't in the hash so this:
h = Hash.new([])
a = h[:k].push(6)
b = h[:x].push(11)
will leave you with [6,11] in both a and b but nothing in h.
If you want to automatically add defaults when you access them, you'll need to use a default_proc, not a simple default:
anagrams = Hash.new { |h, k] h[k] = [ ] }
That will create the entries when you access a non-existent key and give each one a different empty array.
It's not entirely clear what your method is supposed to do, but I think the problem is that you don't have an array to push a value onto.
In Ruby you can pass a block to Hash.new that tells it what to do when you try to access a key that doesn't exist. This is a handy way to automatically initialize values as empty arrays. For example:
hsh = Hash.new {|hsh, key| hsh[key] = [] }
hsh[:foo] << "bar"
p hsh # => { :foo => [ "bar" ] }
In your method (which I assume you're adding to the String class), you would use it like this:
class String
def my_method
anagrams = Hash.new {|hsh, key| hsh[key] = [] }
downcase.scan(/\b[a-z]+/i).each_with_object(anagrams) do |key|
anagrams[key.downcase.chars.sort.join] << key
end
end
end
Is there any way simpler than
if hash.key?('a')
hash['a']['b'] = 'c'
else
hash['a'] = {}
hash['a']['b'] = 'c'
end
The easiest way is to construct your Hash with a block argument:
hash = Hash.new { |h, k| h[k] = { } }
hash['a']['b'] = 1
hash['a']['c'] = 1
hash['b']['c'] = 1
puts hash.inspect
# "{"a"=>{"b"=>1, "c"=>1}, "b"=>{"c"=>1}}"
This form for new creates a new empty Hash as the default value. You don't want this:
hash = Hash.new({ })
as that will use the exact same hash for all default entries.
Also, as Phrogz notes, you can make the auto-vivified hashes auto-vivify using default_proc:
hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
UPDATE: I think I should clarify my warning against Hash.new({ }). When you say this:
h = Hash.new({ })
That's pretty much like saying this:
h = Hash.new
h.default = { }
And then, when you access h to assign something as h[:k][:m] = y, it behaves as though you did this:
if(h.has_key?(:k))
h[:k][:m] = y
else
h.default[:m] = y
end
And then, if you h[:k2][:n] = z, you'll end up assigning h.default[:n] = z. Note that h still says that h.has_key?(:k) is false.
However, when you say this:
h = Hash.new(0)
Everything will work out okay because you will never modified h[k] in place here, you'll only read a value from h (which will use the default if necessary) or assign a new value to h.
a simple one, but hash should be a valid hash object
(hash["a"] ||= {})['b'] = "c"
If you create hash as the following, with default value of a new (identically default-valued) hash: (thanks to Phrogz for the correction; I had the syntax wrong)
hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
Then you can do
hash["a"]["b"] = "c"
without any additional code.
The question here:
Is auto-initialization of multi-dimensional hash array possible in Ruby, as it is in PHP?
provides a very useful AutoHash implementation that does this.
class NilClass
def [](other)
nil
end
end
Once you defined that, everything will work automatically. But be aware that from now on nil would behave as an empty hash when used as a hash.