I am new to Ruby and trying to find if I can create a hash which has keys as keys_Array and values as val_array.
Currently I have the following but it gives empty array.
key_hash = Hash.new { |hash, key|
hash.key = ["#{csv['values']} #{csv['keys']}"]
}
p key_hash.keys #empty array here
If you're trying to create a hash from two corresponding arrays for keys and values, this is quick way:
keys = ["a", "b", "c"]
values = [1, 2, 3]
hash = Hash[keys.zip(values)]
# => {"a"=>1, "b"=>2, "c"=>3}
# for symbols
hash = Hash[keys.map(&:to_sym).zip(values)]
# => {:a=>1, :b=>2, :c=>3}
If you want to make a new hash from two hashes (one contains keys for new hash and other contains values with respect to keys in first hash then only)
you can use something like below :
keys = ['k1', 'k2', 'k3']
values = ['b1', 'b2']
h = {}
keys.zip(values) { |a,b| h[a.to_sym] = b }
# => nil
p h
# => {:k1=>"b1", :k2=>"b2", :k3=>nil}
Keep in mind that if the keys are more and values are less in number then key will have nil value as mentioned in the e.g. but if the keys are less as compare to values then it will now consider the remaining values for e.g.
keys =['b1', 'b2']
=> ["b1", "b2"]
values = ['k1', 'k2', 'k3']
=> ["k1", "k2", "k3"]
h = {}
=> {}
keys.zip(values) { |a,b| h[a.to_sym] = b }
=> nil
p h
{:b1=>"k1", :b2=>"k2"}
I am a Ruby novice. But due to some problem I have to handle the code as our ruby developer is not available. We are using cassandra database to get values from a Ruby (Sinatra) web service and put it into the Cassandra keyspace. But due to some problem , the data is failing to insert.
In the following code partners_daily , partner_monthly etc are column family (tables) in the stats keyspace(database).
if params and !partner_id.nil? and !activity_type.nil?
{
:partners_daily => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
:partners_monthly => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}",
:partners_alltime => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}",
:channels_daily => "#{channel_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
:channels_monthly => "#{channel_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}",
:channels_alltime => "#{channel_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}",
:countries_daily => "#{country}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
:countries_monthly => "#{country}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}",
:countries_alltime => "#{country}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}"
}.each do |k,v|
stats.add(k, v, 1, 'count')
end
return "Activity stored in stats"
end
else
return "Error: client headers missing"
end
end
def count(table, key)
require 'cassandra-cql' # requiring this at the top was leading to error: unconfigured columnfamily
cqldb = CassandraCQL::Database.new('127.0.0.1:9160', {:keyspace => 'plystats'})
query = "update partners_daily set count = ? where key = ?"#"update #{table} set count = count+1 where key = ?;"
#return cqldb.execute(query, 0, 'sonia').inspect
return query
end
I want to know how the data inserting logic in it is being performed, and where ? Is it in stats.add(k, v, 1, 'count') ?
and is there any error in the inserting part because its failing.
I want to know how the data inserting logic in it is being performed, and where ? Is it in stats.add(k, v, 1, 'count') ?
Yes, that's where it should be happening. Between the {} are dictionary/hash values:
{
:partners_daily => # …
}.each do |k,v|
A loop is started with the each method, and each entry is decomposed and put into k and v, the key in k and the value in v. For example, the first record in the hash is:
:partners_daily => "#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
This would then decompose within the each loop to:
k = :partners_daily
v = # The result of
"#{partner_id}_#{activity_type}_#{success == 1 ? 'sucess' : "failure:#{failure_code}"}_#{time.year}_#{time.month}_#{time.day}",
I don't now what the values are for partner_id etc, but making some up it'd look something like "123_sales_sucess_2013_6_01"
Notice there's a typo for the word success in there.
It's a bit confusing due to the multiple double quotes and braces, so I'd change this to:
[partner_id, activity_type, (success == 1 ? 'success' : "failure:#{failure_code}"), time.year, time.month, time.day].join("_")
But notice that there's a lot of repetition in there, so I'd change the whole hash to (at least):
success_string = success == 1 ?
'success' :
"failure:#{failure_code}"
data = {
:partners_daily => [partner_id, activity_type,success_string,time.year,time.month,time.day].join("_"),
:partners_monthly => [partner_id,activity_type,success_string,time.year,time.month].join("_"),
:partners_alltime => [partner_id,activity_type,success_string].join("_"),
:channels_daily => [channel_id,activity_type,success_string,time.year,time.month,time.day].join("_"),
:channels_monthly => [channel_id,activity_type,success_string,time.year,time.month].join("_"),
:channels_alltime => [channel_id,activity_type,success_string].join("_"),
:countries_daily => [country,activity_type,success_string,time.year,time.month,time.day].join("_"),
:countries_monthly => [country,activity_type,success_string,time.year,time.month].join("_"),
:countries_alltime => [country,activity_type,success_string].join("_")
}
data.each do |k,v|
# more code…
It starts to be easier to read and see the logic. Also, by putting the hash into the data variable instead of working on it immediately, it allows you to inspect it more easily, e.g.
warn "data = #{data.inspect}"
would output a representation of the data to the console, so at least you could get an idea of what the script is attempting to put in. At the top of this code, you could also add warn "script = #{script.inspect}" to check what the script object looks like.
If the script object is a Cassandra instance i.e. there's something like script = Cassandra.new "blah", "blahblah" that sets it up, then the add method is this one
The signature given is add(column_family, key, value, *columns_and_options) but that doesn't seem to match the call you have:
stats.add(k, v, 1, 'count')
should (probably) be:
stats.add('count', k, v, 1)
In fact, I'm not even sure that the concatenation in the data hash should happen and maybe all of that should just be passed to add, but it's your data so I can't be sure.
Feel free to comment below and I'll update this.
Trying it in IRB to check it for syntax errors:
success = 1
# => 1
partner_id = 123
# => 123
activity_type = "something"
# => "something"
time = Time.now
# => 2013-06-05 11:17:50 0100
channel_id = 456
# => 456
country = "UK"
# => "UK"
success_string = success == 1 ?
'success' :
"failure:#{failure_code}"
# => "success"
data = {
:partners_daily => [partner_id, activity_type,success_string,time.year,time.month,time.day].join("_"),
:partners_monthly => [partner_id,activity_type,success_string,time.year,time.month].join("_"),
:partners_alltime => [partner_id,activity_type,success_string].join("_"),
:channels_daily => [channel_id,activity_type,success_string,time.year,time.month,time.day].join("_"),
:channels_monthly => [channel_id,activity_type,success_string,time.year,time.month].join("_"),
:channels_alltime => [channel_id,activity_type,success_string].join("_"),
:countries_daily => [country,activity_type,success_string,time.year,time.month,time.day].join("_"),
:countries_monthly => [country,activity_type,success_string,time.year,time.month].join("_"),
:countries_alltime => [country,activity_type,success_string].join("_")
}
# => {:partners_daily=>"123_something_success_2013_6_5", :partners_monthly=>"123_something_success_2013_6", :partners_alltime=>"123_something_success", :channels_daily=>"456_something_success_2013_6_5", :channels_monthly=>"456_something_success_2013_6", :channels_alltime=>"456_something_success", :countries_daily=>"UK_something_success_2013_6_5", :countries_monthly=>"UK_something_success_2013_6", :countries_alltime=>"UK_something_success"}
I have this code here and it works but there has to be a better way.....i need two arrays that look like this
[
{
"Vector Arena - Auckland Central, New Zealand" => {
"2010-10-10" => [
"Enter Sandman",
"Unforgiven",
"And justice for all"
]
}
},
{
"Brisbane Entertainment Centre - Brisbane Qld, Austr..." => {
"2010-10-11" => [
"Enter Sandman"
]
}
}
]
one for the past and one for the upcoming...the problem i have is i am repeating myself and though it works i want to clean it up ...here is my data
..
Try this:
h = Hash.new {|h1, k1| h1[k1] = Hash.new{|h2, k2| h2[k2] = []}}
result, today = [ h, h.dup], Date.today
Request.find_all_by_artist("Metallica",
:select => "DISTINCT venue, showdate, LOWER(song) AS song"
).each do |req|
idx = req.showdate < today ? 0 : 1
result[idx][req.venue][req.showdate] << req.song.titlecase
end
Note 1
In the first line I am initializing an hash of hashes. The outer hash creates the inner hash when a non existent key is accessed. An excerpt from Ruby Hash documentation:
If this hash is subsequently accessed by a key that doesn‘t correspond to a hash
entry, the block will be called with the hash object and the key, and should
return the default value. It is the block‘s responsibility to store the value in
the hash if required.
The inner hash creates and empty array when the non existent date is accessed.
E.g: Construct an hash containing of content as values and date as keys:
Without a default block:
h = {}
list.each do |data|
h[data.date] = [] unless h[data.date]
h[data.date] << data.content
end
With a default block
h = Hash.new{|h, k| h[k] = []}
list.each do |data|
h[data.date] << data.content
end
Second line simply creates an array with two items to hold the past and future data. Since both past and the present stores the data as Hash of Hash of Array, I simply duplicate the value.
Second line can also be written as
result = [ h, h.dup]
today = Date.today