input = {"color"=>["red"],"size"=>["s","l"]}
json_obj = [{"color":"red","id":"123","size":"s","name":"test"},
{"color":"yellow","id":"124","size":"s","name":"test"},
{"color":"red","id":"125","size":"l","name":"test"}]
Output should be
output["red_s"] = {"color":"red","id":"123","size":"s","name":"test"}
output["red_l"] = {"color":"red","id":"125","size":"l","name":"test"}
output is the combinations of the input and a find on the json_obj.
How to get the output in rails?
I have the below script to get the combinations ie.red_s and red_l,
ary = input.map {|k,v| [k].product v}
output = ary.shift.product(*ary).map {|a| Hash[a]}
And
output[red_s]=json_obj.find{|h| h["color"] == "red" and h["size"] == "S"}
I don't want to have any hardcodings in code like color and size as above.
I think this should get you close to what you want.
Note the "ticks" around your json array object (what you had is not valid ruby)
The other issue is you would have to figure a better way to create the output hash key.
require 'json'
input = {"color"=>["red"],"size"=>["s","l"]}
output = {}
json_obj = '[{"color":"red","id":"123","size":"s","name":"test"},
{"color":"yellow","id":"124","size":"s","name":"test"},
{"color":"red","id":"125","size":"l","name":"test"}]'
found = JSON.parse json_obj
input.each_key do |key|
found = found.select { |item| input[key].include?(item[key]) }
end
puts found
found.each do |item|
output_key = ""
input.each_key do |key|
output_key = "#{item[key]}_" + output_key
end
output["#{output_key}"] = item.to_json
end
puts output
Related
Going blind here.. I can't understand why these 2 strings are not equal.. When I puts them to the terminal they are both class string and when I just compare the output they ARE equal. But somehow in my code they are not.. I can't figure out why.
Here is my Ruby code:
def prep_for_duplicate_webhook
#redis_cart = Redis.new
cart_stamp_saved = #redis_cart.get("cart_stamp_saved")
if cart_stamp_saved.nil?
cart_stamp_saved = {}
cart_stamp_saved[:token] = cart_params['token']
cart_stamp_saved[:updated_at] = cart_params['updated_at']
#redis_cart.set("cart_stamp_saved", cart_stamp_saved.to_json)
end
#cart_stamp_incoming = {}
#cart_stamp_incoming["token"] = cart_params['token']
#cart_stamp_incoming["updated_at"] = cart_params['updated_at']
end
def duplicate_webhook?
prep_for_duplicate_webhook
#cart_stamp_saved = redis_cart.get("cart_stamp_saved")
cart_stamp_saved == cart_stamp_incoming.to_json
end
And then the hash's I'm comparing are these two:
cart_stamp_saved = {"token"=>"4a093432ba5c430dd545b16c0e89f187",
"updated_at"=>"2017-02-17T15:27:22.923Z"}
cart_stamp_incoming= {"token"=>"4a093432ba5c430dd545b16c0e89f187",
"updated_at"=>"2017-02-17T15:27:22.923Z"}
If I just copy and paste the above into a new page, and the do this, the response is true
pp cart_stamp_saved == cart_stamp_incoming.to_json
What am I missing?
I encounter a strange problem when trying to alter values from a Hash. I have the following setup:
myHash = {
company_name:"MyCompany",
street:"Mainstreet",
postcode:"1234",
city:"MyCity",
free_seats:"3"
}
def cleanup string
string.titleize
end
def format
output = Hash.new
myHash.each do |item|
item[:company_name] = cleanup(item[:company_name])
item[:street] = cleanup(item[:street])
output << item
end
end
When I execute this code I get: "TypeError: no implicit conversion of Symbol into Integer" although the output of item[:company_name] is the expected string. What am I doing wrong?
Your item variable holds Array instance (in [hash_key, hash_value] format), so it doesn't expect Symbol in [] method.
This is how you could do it using Hash#each:
def format(hash)
output = Hash.new
hash.each do |key, value|
output[key] = cleanup(value)
end
output
end
or, without this:
def format(hash)
output = hash.dup
output[:company_name] = cleanup(output[:company_name])
output[:street] = cleanup(output[:street])
output
end
This error shows up when you are treating an array or string as a Hash. In this line myHash.each do |item| you are assigning item to a two-element array [key, value], so item[:symbol] throws an error.
You probably meant this:
require 'active_support/core_ext' # for titleize
myHash = {company_name:"MyCompany", street:"Mainstreet", postcode:"1234", city:"MyCity", free_seats:"3"}
def cleanup string
string.titleize
end
def format(hash)
output = {}
output[:company_name] = cleanup(hash[:company_name])
output[:street] = cleanup(hash[:street])
output
end
format(myHash) # => {:company_name=>"My Company", :street=>"Mainstreet"}
Please read documentation on Hash#each
myHash.each{|item|..} is returning you array object for item iterative variable like the following :--
[:company_name, "MyCompany"]
[:street, "Mainstreet"]
[:postcode, "1234"]
[:city, "MyCity"]
[:free_seats, "3"]
You should do this:--
def format
output = Hash.new
myHash.each do |k, v|
output[k] = cleanup(v)
end
output
end
Ive come across this many times in my work, an easy work around that I found is to ask if the array element is a Hash by class.
if i.class == Hash
notation like i[:label] will work in this block and not throw that error
end
I have an array in the following form:
[\"id\", 545, \"program_name\", \"VILLIANS MARATHON\", \"episode_name\", \"1-Season1:Ep.11\"]
I need to transform it to the form below:
[545, \"VILLIANS MARATHON\", \"1-Season1:Ep.11\"]
The way Im doing this is as follows:
#Convert a Active record hash to a 2D array
def activerecord_hash_to_datatable_array(activerecord_resultset)
array_of_arrays = Array.new()
array_of_rs_hashes = activerecord_resultset.to_a.map(&:serializable_hash)
array_of_rs_hashes.each do |rs|
# {"id"=>1594, "program_name"=>nil, "episode_name"=>nil}
rs = rs.flatten
#[\"id\", 545, \"program_name\", \"MARATHON\", \"episode_name\", \"1-Season1:Ep.11\"]"
rs_array = Array.new()
index = 1
while index < rs.length
puts "index = #{index}"
puts "\033[0;33m"+"#{rs[index]}"+"\033[0;37m"
log_with_yellow("index[#{index}] " + "#{rs[index]}")
rs_array << rs[index]
index += 2
end
array_of_arrays << rs_array
end
array_of_arrays
end
I was wondering what the most efficient way to accomplish this is.
Clearly I need to retain only odd elements. But Id like to avoid iterating over all elements and comparing each elements index.
Is there a way to do this by skipping all the even elements ?
Thanks
You can do the following:
your_array.values_at(*your_array.each_index.select(&:odd?))
=> [545, "VILLIANS MARATHON", "1-Season1:Ep.11"]
require 'json'
arr = JSON.parse("[\"id\", 545, \"program_name\", \"VILLIANS MARATHON\", \"episode_name\", \"1-Season1:Ep.11\"]")
new_arr = arr.select.with_index { |x,i| i.odd? }
p new_arr
# >> [545, "VILLIANS MARATHON", "1-Season1:Ep.11"]
If array_of_rs_hashes is indeed an array of hashes, can't you just do:
res = array_of_rs_hashes.map(&:values)
Yep there is :
require 'json'
Hash[*JSON.parse(s)].values #=> [545, "VILLIANS MARATHON", "1-Season1:Ep.11"]
where s = "[\"id\", 545, \"program_name\", \"VILLIANS MARATHON\", \"episode_name\", \"1-Season1:Ep.11\"]"
Try:
your_2d_array.map {|a| a.each_slice(2).map {|key, value| value}}
If you ahve active support, you can write it slightly more readible:
your_2d_array.map {|a| a.each_slice(2).map(&:second)}
I do the following
my_hash = Hash.new
my_hash[:children] = Array.new
I then have a function that calls itself a number of time each time writing to children
my_hash[:children] = my_replicating_function(some_values)
How do I write without overwriting data that is already written ?
This is what the entire function looks like
def self.build_structure(candidates, reports_id)
structure = Array.new
candidates.each do |candidate, index|
if candidate.reports_to == reports_id
structure = candidate
structure[:children] = Array.new
structure[:children] = build_structure(candidates, candidate.candidate_id)
end
end
structure
end
Maybe this:
structure[:children] << build_structure(candidates, candidate.candidate_id)
structure[:children] << build_structure(candidates, candidate.candidate_id)
Not sure this isn't working.
>> params[:payments]
{"0"=>{":amount_paid"=>"80.00", ":date_paid"=>"2/27/2008"}, "1"=>{":amount_paid"=>"100.00", ":date_paid"=>"5/8/2008"}}
So I can call a specific object with this :
>> params[:payments][:"1"]
{":amount_paid"=>"100.00", ":date_paid"=>"5/8/2008"}
But if I write this..
>> params[:payments].each_with_index{|item, idx| item[:"#{idx}"]}
TypeError Exception: Symbol as array index
Idealistically, I want to accomplish this :
params[:payments].each_with_index do |item, idx|
#calc.payments[idx][:date_paid] = item[:"#{idx}"][":amount_paid"]
#calc.payments[idx][:amount_paid] = (item[:"#{idx}"][":amount_paid"]).to_f
end
Update:
Based on some answers, I'ved tried this :
params[:payments].each{|k,v| #calc.payments[k.to_i] = v[":amounts_paid"]}
This turns #calc.payments into :
nil
nil
Backing up though, the others seem to work..
>> params[:payments].each{|k,v| p v[":amount_paid"]}
"80.00"
"100.00"
And this one..
>> params[:payments].each{|k,v| p #calc.payments[k.to_i]}
{:date_awarded=>"1/2/2008", :judgement_balance=>1955.96}
nil
How can I access item[idx] in a loop?
params[:payments].each do |k,v|
puts "Item %d amount=%s date=%s\n" % [k, v[":amount_paid"], v[":date_paid"]]
end
Item 0 amount=80.00 date=2/27/2008
Item 1 amount=100.00 date=5/8/2008
Update:
Ok, ok, here is a complete program .. script .. that you can actually run. Since you are trying to make sense of Ruby I think you should work with it outside of Rails for a few minutes. I mocked up #calc.payments, whatever that is. This code will run and apparently do what you want.
require 'pp'
(params = {})[:payments] = {"0"=>{":amount_paid"=>"80.00", ":date_paid"=>"2/27/2008"}, "1"=>{":amount_paid"=>"100.00", ":date_paid"=>"5/8/2008"}}
pp params
class T; attr_accessor :payments; end
(#calc = T.new).payments = []
params[:payments].each do |k,v|
i = k.to_i
#calc.payments[i] ||= {}
#calc.payments[i][:date_paid] = v[":date_paid"]
#calc.payments[i][:amount_paid] = v[":date_paid"].to_f
end
pp #calc.payments
If you run it you should see:
{:payments=>
{"0"=>{":amount_paid"=>"80.00", ":date_paid"=>"2/27/2008"},
"1"=>{":amount_paid"=>"100.00", ":date_paid"=>"5/8/2008"}}}
[{:date_paid=>"2/27/2008", :amount_paid=>2.0},
{:date_paid=>"5/8/2008", :amount_paid=>5.0}]
You could just do a this to access the values. Since params[:payments] contains a hash, then for each pass through, key, will be assigned the "0", "1", etc., and value will be assigned the hash with amount_paid and date_paid.
params[:payments].each do |key, value|
amount_paid = value[":amount_paid"]
...
end