Convert string into variable within for loop - ruby

Given the following code in RUBY, I need to loop through a bunch of hashes. The problem is, varX is a string, I need it to be a variable. Any ideas?
element1_old = {:ip => "192.168.0.191", :state => "PA", :county => "ambler"}
element1_new = {:ip => "192.168.0.191", :state => "PA", :county => "warrington"}
element2_old = {:ip => "192.168.0.192", :state => "PA", :county => "ambler"}
element2_new = {:ip => "192.168.0.192", :state => "PA", :county => "ambler"}
element3_old = {:ip => "192.168.0.200", :state => "PA", :county => "warrington"}
element3_new = {:ip => "192.168.0.200", :state => "PA", :county => "ambler"}
for i in 1..3
var1 = "element#{i}_old"
var2 = "element#{i}_new"
p element"#{i}".not_in_both("element#{i}_old")
end

Throw the hashes into another hash:
h = {
'element1_old' => {:ip => "192.168.0.191", :state => "PA", :county => "ambler"},
'element1_new' => {:ip => "192.168.0.191", :state => "PA", :county => "warrington"},
'element2_old' => {:ip => "192.168.0.192", :state => "PA", :county => "ambler"},
'element2_new' => {:ip => "192.168.0.192", :state => "PA", :county => "ambler"},
'element3_old' => {:ip => "192.168.0.200", :state => "PA", :county => "warrington"},
'element3_new' => {:ip => "192.168.0.200", :state => "PA", :county => "ambler"}
}
for i in 1..3
old = h["element#{i}_old"]
new = h["element#{i}_new"]
p new.not_in_both(old)
end
I'm assuming that element"#{i}" is actually supposed to be element"#{i}"_new in your pseudo-Ruby example and that you have monkey patched not_in_both into Hash.

Related

Fedex Ruby Gem: Customs Value is required - how to add?

I'm working with the Ruby gem 'FedEx', https://github.com/jazminschroeder/fedex.
I've set up my code for a development mode and I'm testing making a shipment.
However, I get stuck with the following error:
C:/Ruby22/lib/ruby/gems/2.2.0/gems/fedex-.10.1/lib/fedex/request/shipment.rb:134:in 'failure_response': Customs Value is required. (Fedex:: RateError) from C: /Ruby22/lib/ruby/gems/2.2.0/gems/fedex-.10.1/lib/fedex/request/shipment.rb:32:in 'process_request' from C: /Ruby22/lib/ruby/gems/2.2.0/gems/fedex-3.10.1/lib/fedex/shipment.rb:57:in 'ship' from C: /Ruby22/bin/css_fedex_v1.rb:92:in ''
It seems that I need to parse a 'Customs Value', probably as part of my 'packages' hash. However, I'm unable to find the relevant field for me to enter this in. Anyone who's experienced this and found a solution?
My code is as below:
require 'fedex'
fedex = Fedex::Shipment.new(:key => '***',
:password => '***',
:account_number => '***',
:meter => '***',
:mode => 'development')
shipper = { :name => "***",
:company => "***",
:phone_number => "***",
:address => "***",
:city => "***",
:postal_code => "***",
:country_code => "DK" }
recipient = { :name => "***",
:company => "***",
:phone_number => "***",
:address => "***",
:city => "***",
:postal_code => "***",
:country_code => "GB",
:residential => "false" }
packages = []
packages << {:weight => {:units => "LB", :value => 1}}
shipping_options = {:packaging_type => "YOUR_PACKAGING",
:drop_off_type => "REGULAR_PICKUP"}
rate = fedex.rate(:shipper=>shipper,
:recipient => recipient,
:packages => packages,
:shipping_options => shipping_options)
ship = fedex.ship(:shipper=>shipper,
:recipient => recipient,
:packages => packages,
:service_type => "INTERNATIONAL_PRIORITY",
:shipping_options => shipping_options)
puts ship[:completed_shipment_detail][:operational_detail][:transit_time]
Customs value is declared in their docs:
https://github.com/jazminschroeder/fedex/commit/9f1d4c67b829aaa4eeba9090c1a45d3bd507aab3#diff-4f122efb7c0d98120d8b7f0cd00998e4R106
customs_value = { :currency => "USD",
:amount => "200" }
As I understand you can pass it into the commodities hash or keep it separate.

ruby-aws Amazon Mechanical Turk

I am trying to create a HIT with a pre-created form using the ruby-aws gem and keep getting a missing params error. I have limited the missing params to the params specific to my form.
It seems my request is not being formatted correctly and there are next to no examples from Amazon. My logs say the the following params are missing:
relationship, price, environmental_consciousness, age, occasion, gender, humor, experience, local, romance, additional_information
Any help is much appreciated!
Below is my current request:
hit = mturk.createHIT(
:Operation => 'CreateHIT',
:Title => 'Find a gift based on user scores',
:Description => 'Find a gift for an individual based on survey scores.',
:MaxAssignments => 3,
:Signature => signature,
:Timestamp => timestamp,
:Reward => { :Amount => 0.25, :CurrencyCode => 'USD' },
:HITLayoutId => '3AV6FF2M2GYMGLRQEKHZ7EBN4EZOJE',
:HitLayoutParameter => {'Name' => 'additional_information', 'Value' => 'TEST'},
:HitLayoutParameter => {'Name' => 'age', 'Value' => '22'},
:HitLayoutParameter => {'Name' => 'environmental_consciousness', 'Value' => '54'},
:HitLayoutParameter => {'Name' => 'experience', 'Value' => '32'},
:HitLayoutParameter => {'Name' => 'gender', 'Value' => 'male'},
:HitLayoutParameter => {'Name' => 'humor', 'Value' => '66'},
:HitLayoutParameter => {'Name' => 'local', 'Value' => '21'},
:HitLayoutParameter => {'Name' => 'occasion', 'Value' => '43'},
:HitLayoutParameter => {'Name' => 'price', 'Value' => '33'},
:HitLayoutParameter => {'Name' => 'relationship', 'Value' => '23'},
:HitLayoutParameter => {'Name' => 'romance', 'Value' => '23'},
:Keywords => 'data collection, gifting, gifts, shopping, gift listings, presents',
:AssignmentDurationInSeconds => 300,
:LifetimeInSeconds => 604800
)
I was able to resolive the issue - AWS has terrible naming conventions. The above example does use the correct format, however HitLayoutParameter must be HITLayoutParameter - Notice the CAPITAL HIT vs Hit.
Also, when submitting multiple parameters, the should only be one HITLayoutParameter that equals an array of Name/Value pairs. Working code below.
Hope this helps someone else!
Best,
~DFO~
hit = mturk.createHIT(
:Operation => 'CreateHIT',
:Title => 'Find a gift based on user scores',
:Description => 'Find a gift for an individual based on survey scores.',
:MaxAssignments => 3,
:Signature => signature,
:Timestamp => timestamp,
:Reward => { :Amount => 0.25, :CurrencyCode => 'USD' },
:HITLayoutId => '3AV6FF2M2GYMGLRQEKHZ7EBN4EZOJE',
:HITLayoutParameter => [
{:Name => 'additional_information', :Value => 'TEST'},
{:Name => 'age', :Value => '22'},
{:Name => 'environmental_consciousness', :Value => '54'},
{:Name => 'experience', :Value => '32'},
{:Name => 'gender', :Value => 'male'},
{:Name => 'humor', :Value => '66'},
{:Name => 'local', :Value => '21'},
{:Name => 'occasion', :Value => '43'},
{:Name => 'price', :Value => '33'},
{:Name => 'relationship', :Value => '23'},
{:Name => 'romance', :Value => '23'}
],
:Keywords => 'data collection, gifting, gifts, shopping, gift listings, presents',
:AssignmentDurationInSeconds => 300,
:LifetimeInSeconds => 604800
)

How to count values in a array of hashes

I have an array of hashes
[ {:name => "bob", :type => "some", :product => "apples"},
{:name => "ted", :type => "other", :product => "apples"},....
{:name => "Will", :type => "none", :product => "oranges"} ]
and was wondering if there is a simple way to count the number of product's and store the count as well as the value in an array or hash.
I want the result to be something like:
#products = [{"apples" => 2, "oranges => 1", ...}]
You can do as
array = [
{:name => "bob", :type => "some", :product => "apples"},
{:name => "ted", :type => "other", :product => "apples"},
{:name => "Will", :type => "none", :product => "oranges"}
]
array.each_with_object(Hash.new(0)) { |h1, h2| h2[h1[:product]] += 1 }
# => {"apples"=>2, "oranges"=>1}
You can use Enumerable#group_by and Enumerable#map
array.group_by{|h| h[:product]}.map{|k,v| [k, v.size]}.to_h
# => {"apples"=>2, "oranges"=>1}
While not exactly what the OP was looking for, this may be helpful to many. If you're just looking for the count of a specific product, you could do this:
array = [
{:name => "bob", :type => "some", :product => "apples"},
{:name => "ted", :type => "other", :product => "apples"},
{:name => "Will", :type => "none", :product => "oranges"}
]
array.count { |h| h[:product] == 'apples' }
# => 2
You could count:
hashes = [
{:name => "bob", :type => "some", :product => "apples"},
{:name => "ted", :type => "other", :product => "apples"},
{:name => "Will", :type => "none", :product => "oranges"}
]
hashes.inject(Hash.new(0)) { |h,o| h[o[:product]] += 1; h }
Or maybe...
hashes.instance_eval { Hash[keys.map { |k| [k,count(k)] }] }
I do not know which is the more performant, the latter seims weird to read though.
I would do:
items =[ {:name => "bob", :type => "some", :product => "apples"},
{:name => "ted", :type => "other", :product => "apples"},
{:name => "Will", :type => "none", :product => "oranges"} ]
counts = items.group_by{|x|x[:product]}.map{|x,y|[x,y.count]}
p counts #=> [["apples", 2], ["oranges", 1]]
Then if you need it as a Hash just do:
Hash[counts]

Ruby array of hashes, compare 2 keys and sum another key/value

In Ruby I have the following array of hashes:
[
{:qty => 1, :unit => 'oz', :type => 'mass'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'},
{:qty => 1, :unit => 'lbs', :type => 'mass'}
]
What I need to be able to do is compare the elements by the :unit and :type and then sum the :qty when they are the same. The resulting Array should look like follows:
[
{:qty => 5, :unit => 'oz', :type => 'mass'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 1, :unit => 'lbs', :type => 'mass'}
]
If the array has multiple hashes where the :qty is nil and the :unit is empty (""), then it would only return one of those. So to extend the above example, this:
[
{:qty => 1, :unit => 'oz', :type => 'mass'},
{:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'},
{:qty => 1, :unit => 'lbs', :type => 'mass'},
{:qty => nil, :unit => '', :type => 'Foo'}
]
would become this:
[
{:qty => 5, :unit => 'oz', :type => 'mass'},
{:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 1, :unit => 'lbs', :type => 'mass'}
]
EDIT: Sorry, made a mistake in the second example... it shouldn't have the o.
Start by using group_by with the keys you want, then reduce the qtys in each value into a single hash, or instead using nil if they are all nil:
properties.group_by do |property|
property.values_at :type, :unit
end.map do |(type, unit), properties|
quantities = properties.map { |p| p[:qty] }
qty = quantities.all? ? quantities.reduce(:+) : nil
{ type: type, unit: unit, qty: qty }
end
#=> [{:type=>"mass", :unit=>"oz", :qty=>5},
# {:type=>"Foo", :unit=>"", :qty=>nil},
# {:type=>"vol", :unit=>"oz", :qty=>5},
# {:type=>"mass", :unit=>"lbs", :qty=>1}]
Where properties is your second sample input data.
You're going to want enumberable.group_by
This should get you started
items.group_by { |item| item.values_at(:unit, :type) }
Output
{
["oz", "mass"]=> [
{:qty=>1, :unit=>"oz", :type=>"mass"},
{:qty=>4, :unit=>"oz", :type=>"mass"}
],
["oz", "vol"]=>[
{:qty=>5, :unit=>"oz", :type=>"vol"}
],
["lbs", "mass"]=>[
{:qty=>1, :unit=>"lbs", :type=>"mass"}
]
}
ar = [{:qty => 1, :unit => 'oz', :type => 'mass'}, {:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'}, {:qty => 1, :unit => 'lbs', :type => 'mass'},
{:qty => nil, :unit => 'o', :type => 'Foo'}]
result = ar.each_with_object(Hash.new(0)) do |e,hsh|
if hsh.has_key?({:unit => e[:unit], :type => e[:type]})
hsh[{:unit => e[:unit], :type => e[:type]}] += e[:qty]
else
hsh[{:unit => e[:unit], :type => e[:type]}] = e[:qty]
end
end
result.map{|k,v| k[:qty] = v;k }.delete_if{|h| h[:qty].nil? and !h[:unit].empty? }
# => [{:unit=>"oz", :type=>"mass", :qty=>5},
# {:unit=>"", :type=>"Foo", :qty=>nil},
# {:unit=>"oz", :type=>"vol", :qty=>5},
# {:unit=>"lbs", :type=>"mass", :qty=>1}]
Taking #Andrew Marshall under consideration
ar = [{:qty => 1, :unit => 'oz', :type => 'mass'}, {:qty => nil, :unit => '', :type => 'Foo'},
{:qty => 5, :unit => 'oz', :type => 'vol'},
{:qty => 4, :unit => 'oz', :type => 'mass'}, {:qty => 1, :unit => 'lbs', :type => 'mass'},
{:qty => nil, :unit => 'o', :type => 'Foo'}]
result = ar.each_with_object(Hash.new(0)) do |e,hsh|
if hsh.has_key?({:unit => e[:unit], :type => e[:type]})
hsh[{:unit => e[:unit], :type => e[:type]}] += e[:qty]
else
hsh[{:unit => e[:unit], :type => e[:type]}] = e[:qty]
end
end
result.map{|k,v| k[:qty] = v;k }.delete_if{|h| h[:qty].nil? and h[:unit].empty? }
# => [{:unit=>"oz", :type=>"mass", :qty=>5},
# {:unit=>"oz", :type=>"vol", :qty=>5},
# {:unit=>"lbs", :type=>"mass", :qty=>1},
# {:unit=>"o", :type=>"Foo", :qty=>nil}]

How can i get a hash into an array, state and acronym?

Array = [{:acronym => "AC", :fullname => "Acre"}, {:acronym => "AL", :fullname => "Alagoas"}, {:acronym => "AP", :fullname => "Amapá"}, {:acronym => "AM", :fullname => "Amazonas"}, {:acronym => "BA", :fullname => "Bahia"}, {:acronym => "CE", :fullname => "Ceará"}, {:acronym => "DF", :fullname => "Distrito Federal"}, {:acronym => "ES", :fullname => "Espírito Santo"}, {:acronym => "GO", :fullname => "Goiás"}, {:acronym => "MA", :fullname => "Maranhão"}, {:acronym => "MT", :fullname => "Mato Grosso"}, {:acronym => "MS", :fullname => "Mato Grosso do Sul"}, {:acronym => "MG", :fullname => "Minas Gerais"}, {:acronym => "PA", :fullname => "Pará"}, {:acronym => "PB", :fullname => "Paraíba"}, {:acronym => "PR", :fullname => "Paraná"}, {:acronym => "PE", :fullname => "Pernambuco"}, {:acronym => "PI", :fullname => "Piauí"}, {:acronym => "RR", :fullname => "Roraima"}, {:acronym => "RO", :fullname => "Rondônia"}, {:acronym => "RJ", :fullname => "Rio de Janeiro"}, {:acronym => "RN", :fullname => "Rio Grande do Norte"}, {:acronym => "RS", :fullname => "Rio Grande do Sul"}, {:acronym => "SC", :fullname => "Santa Catarina"}, {:acronym => "SP", :fullname => "São Paulo"}, {:acronym => "SE", :fullname => "Sergipe"}, {:acronym => "TO", :fullname => "Tocantins"}]
How can I compare a variable with :acronym and return the :fullname in other variable?
I'm trying to do this using a Rails helper.
First of all you don't want to call your array Array as that's a class name and it is already taken.
You could do this:
def find_acronym_in(array, acronym)
# returns nil if we don't find a match.
array.find { |h| h[:acronym] == acronym }.try(:fetch, :fullname)
end
and in your ERB:
<%= find_acronym_in(#acronyms, 'ES') %>
That's a simple linear search so it will be slow for large lists but it probably won't be noticeable for short lists.
If you're doing a lot of this or if you have large lists then you could rearrange your array into a simple Hash in your controller:
#acronyms_hash = #acronyms.each_with_object({ }) { |h, memo| memo[h[:acronym]] = h[:fullname] }
and then just pull things out of the Hash as needed:
<%= #acronyms_hash['ES'] %>
This will do it
acronym_to_find = "SE"
Array.select { |ac| ac[:acronym] == acronym_to_find }.first[:fullname]
Your data would probably be better structured as a hash of { acronym => fullname} pairs, though.

Resources