How do I create a hash from a querystring in ruby? [duplicate] - ruby

This question already has answers here:
Parse a string as if it were a querystring in Ruby on Rails
(5 answers)
Closed 9 years ago.
I want to create a hash from a querystring. This is my method:
def qs2h(querystring)
hashes = querystring.split('&').inject({}) do |result,query|
k,v = query.split('=')
if !v.nil?
result.merge(k.to_sym => v)
elsif !result.key?(k)
result.merge(k.to_sym => true)
else
result
end
end
hashes
end
qs2h('a=1&b=2&c=3&d') #=> {:a => "1", :b => "2", :c => "3", :d => true}
Is there any simpler method to do this in ruby?

Use CGI::parse:
CGI.parse('a=1&b=2&c=3&d')
# => {"a"=>["1"], "b"=>["2"], "c"=>["3"], "d"=>[]}
Hash[CGI.parse('a=1&b=2&c=3&d').map {|key,values| [key.to_sym, values[0]||true]}]
# => {:a=>"1", :b=>"2", :c=>"3", :d=>true}

Related

why there is a column ":" in front of key in ruby [duplicate]

This question already has answers here:
Is there any difference between the `:key => "value"` and `key: "value"` hash notations?
(5 answers)
Closed 1 year ago.
aaa = { :one => "eins", :two => "zwei", :three => "drei" }
bbb = { one: "eins", two: "zwei", three: "drei" }
above are valid ruby code. at line 1, why there is ":" before "one"? What's the meaning?
It's called Symbol, you could think of it as a special string. Symbols are often used as hash keys.
You could check out more on Ruby Symbols vs. Strings
In ruby hash is an association of key and value.
my_hash = { :key => "value" }
or
my_hash = { key: "value" }
more informations here : https://launchschool.com/books/ruby/read/hashes

how can I programmatically identify which keys have sub key-value-pairs in a JSON doc? [duplicate]

This question already has answers here:
Flattening nested hash to a single hash with Ruby/Rails
(6 answers)
Closed 8 years ago.
I fetch a JSON document and need to programmatically "flatten" the keys for another third-party service.
What this means is, if my JSON doc comes back with the following:
{'first_name' => "Joe", 'hoffman' => {'patterns' => ['negativity', 'self-sabotage'], 'right_road' => 'happy family'}, 'mbti' => 'INTJ'}
I need to be able to know to create a "flat" key-value pair for a third-party service like this:
first_name = "Joe"
hoffman.patterns = "negativity, self-sabotage"
hoffman.right_road = "happy family"
mbti = "INTJ"
Once I know there's a sub-document, the parsing I think I have figured out just appending the sub-keys with key + '.' + "{subkey}" but right now, don't know which ones are straight key-value and which one's have sub-documents.
Question:
a) How can I parse the JSON to know which keys have sub-documents (additional key-values)?
b) Suggestions on ways to create a string from an array
You could also monkey patch Hash to do this on it's own like so:
class Hash
def flatten_keys(prefix=nil)
each_pair.map do |k,v|
key = [prefix,k].compact.join(".")
v.is_a?(Hash) ? v.flatten_keys(key) : [key,v.is_a?(Array) ? v.join(", ") : v]
end.flatten.each_slice(2).to_a
end
def to_flat_hash
Hash[flatten_keys]
end
end
Then it would be
require 'json'
h = JSON.parse(YOUR_JSON_RESPONSE)
#=> {'first_name' => "Joe", 'hoffman' => {'patterns' => ['negativity', 'self-sabotage'], 'right_road' => 'happy family'}, 'mbti' => 'INTJ'}
h.to_flat_hash
#=> {"first_name"=>"Joe", "hoffman.patterns"=>"negativity, self-sabotage", "hoffman.right_road"=>"happy family", "mbti"=>"INTJ"}
Will work with additional nesting too
h = {"first_name"=>"Joe", "hoffman"=>{"patterns"=>["negativity", "self-sabotage"], "right_road"=>"happy family", "wrong_road"=>{"bad_choices"=>["alcohol", "heroin"]}}, "mbti"=>"INTJ"}
h.to_flat_hash
#=> {"first_name"=>"Joe", "hoffman.patterns"=>"negativity, self-sabotage", "hoffman.right_road"=>"happy family", "hoffman.wrong_road.bad_choices"=>"alcohol, heroin", "mbti"=>"INTJ"}
Quick and dirty recursive proc:
# assuming you've already `JSON.parse` the incoming json into this hash:
a = {'first_name' => "Joe", 'hoffman' => {'patterns' => ['negativity', 'self-sabotage'], 'right_road' => 'happy family'}, 'mbti' => 'INTJ'}
# define a recursive proc:
flatten_keys = -> (h, prefix = "") do
#flattened_keys ||= {}
h.each do |key, value|
# Here we check if there's "sub documents" by asking if the value is a Hash
# we also pass in the name of the current prefix and key and append a . to it
if value.is_a? Hash
flatten_keys.call value, "#{prefix}#{key}."
else
# if not we concatenate the key and the prefix and add it to the #flattened_keys hash
#flattened_keys["#{prefix}#{key}"] = value
end
end
#flattened_keys
end
flattened = flatten_keys.call a
# => "first_name"=>"Joe", "hoffman.patterns"=>["negativity", "self-sabotage"], "hoffman.right_road"=>"happy family", "mbti"=>"INTJ"}
And then, to turn the arrays into strings just join them:
flattened.inject({}) do |hash, (key, value)|
value = value.join(', ') if value.is_a? Array
hash.merge! key => value
end
# => {"first_name"=>"Joe", "hoffman.patterns"=>"negativity, self-sabotage", "hoffman.right_road"=>"happy family", "mbti"=>"INTJ"}
Another way, inspired by this post:
def flat_hash(h,f=[],g={})
return g.update({ f=>h }) unless h.is_a? Hash
h.each { |k,r| flat_hash(r,f+[k],g) }
g
end
h = { :a => { :b => { :c => 1,
:d => 2 },
:e => 3 },
:f => 4 }
result = {}
flat_hash(h) #=> {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4}
.each{ |k, v| result[k.join('.')] = v } #=> {"a.b.c"=>1, "a.b.d"=>2, "a.e"=>3, "f"=>4}

how to sum values inside array hash with same key in ruby [duplicate]

This question already has answers here:
Group hashes by keys and sum the values
(5 answers)
Closed 8 years ago.
i want to sum values inside array hash with same key in ruby, example :
a = [{"nationalvoice"=>"5"}, {"nationalvoice"=>"1"}]
how to make the array of hash to like this :
a = [{"nationalvoice"=>"6"}]
My functional solution
array = [{"foo" => "1"}, {"bar" => "2"}, {"foo" => "4"}]
array.group_by { |h| h.keys.first }.map do |k, v|
Hash[k, v.reduce(0) { |acc, n| acc + n.values.first.to_i }]
end
# => [{"foo"=>5}, {"bar"=>2}]
[{"nationalvoice"=>"5"}, {"nationalvoice"=>"1"}]
.group_by{|h| h.keys.first}.values
.map{|a| {
a.first.keys.first =>
a.inject(0){|sum, h| sum + h.values.first.to_i}.to_s
}}
# => [{"nationalvoice"=>"6"}]
Simple way:
[{ "nationalvoice" => [{"nationalvoice"=>"5"}, {"nationalvoice"=>"1"}].reduce(0) {|s, v| s + v.values.first.to_i } }]
# => [{"nationalvoice"=>6}]
with #replace:
a = [{"nationalvoice"=>"5"}, {"nationalvoice"=>"1"}]
a.replace( [{ a.first.keys.first => a.reduce(0) {|s, v| s + v.values.first.to_i } }] )
# => [{"nationalvoice"=>6}]
I'd do as below :
a = [{"nationalvoice"=>"1"}, {"foo" => "1"}, {"bar" => "2"}, {"nationalvoice"=>"5"}]
new = a.group_by { | h | h.keys.first }.map do |k,v|
v.each_with_object({}) do | h1,h2|
h2.merge!(h1) { |key,old,new| (old.to_i + new.to_i).to_s }
end
end
new # => [{"nationalvoice"=>"6"}, {"foo"=>"1"}, {"bar"=>"2"}]

Ruby - array with indexes

how can I do in Ruby an array with indexes?
My custom from PHP is something like this:
#my_array = [0 => "a", 3 => "bb", 7 => "ccc"]
And this array I want to go through each_with_index and I would like to get the result, e.g. in a shape:
0 - a
3 - bb
7 - ccc
Can anyone help me, how to do?
Thanks
They're called hashes in ruby.
h = { 0 => "a", 3 => "bb", 7 => "ccc" }
h.each {|key, value| puts "#{key} = #{value}" }
Reference with a bunch of examples here: Hash.
You don't want an array, you want to use a hash. Since your indices are not sequential (as they would/should be if using an array), use a hash like so:
#my_hash = { 0 => 'a', 3 => 'bb', 7 => 'ccc' }
Now you can iterate through it like this:
#my_hash.each do |key, value|
num = key
string = value
# do stuff
end
Arrays in ruby already have indexes but if you want an associative array with index of your choice, use a Hash:
#my_array = {0 => "a", 3 => "bb", 7 => "ccc"}

hash assignment when (key => value) are stored in an array? (ruby)

I have hash (#post) of hashes where I want to keep the order of the hash's keys in the array (#post_csv_order) and also want to keep the relationship key => value in the array.
I don't know the final number of both #post hashes and key => value elements in the array.
I don't know how to assign the hash in a loop for all elements in the array. One by one #post_csv_order[0][0] => #post_csv_order[0][1] works nicely.
# require 'rubygems'
require 'pp'
#post = {}
forum_id = 123 #only sample values.... to make this sample script work
post_title = "Test post"
#post_csv_order = [
["ForumID" , forum_id],
["Post title", post_title]
]
if #post[forum_id] == nil
#post[forum_id] = {
#post_csv_order[0][0] => #post_csv_order[0][1],
#post_csv_order[1][0] => #post_csv_order[1][1]
##post_csv_order.map {|element| element[0] => element[1]}
##post_csv_order.each_index {|index| #post_csv_order[index][0] => #post_csv_order[index][1] }
}
end
pp #post
desired hash assignment should be like that
{123=>{"Post title"=>"Test post", "ForumID"=>123}}
The best way is to use to_h:
[ [:foo,1],[:bar,2],[:baz,3] ].to_h #=> {:foo => 1, :bar => 2, :baz => 3}
Note: This was introduced in Ruby 2.1.0. For older Ruby, you can use my backports gem and require 'backports/2.1.0/array/to_h', or else use Hash[]:
array = [[:foo,1],[:bar,2],[:baz,3]]
# then
Hash[ array ] #= > {:foo => 1, :bar => 2, :baz => 3}
This is available in Ruby 1.8.7 and later. If you are still using Ruby 1.8.6 you could require "backports/1.8.7/hash/constructor", but you might as well use the to_h backport.
I am not sure I fully understand your question but I guess you want to convert a 2d array in a hash.
So suppose you have an array such as:
array = [[:foo,1],[:bar,2],[:baz,3]]
You can build an hash with:
hash = array.inject({}) {|h,e| h[e[0]] = e[1]; h}
# => {:foo=>1, :bar=>2, :baz=>3}
And you can retrieve the keys in correct order with:
keys = array.inject([]) {|a,e| a << e[0] }
=> [:foo, :bar, :baz]
Is it what you were looking for ?
Answers summary
working code #1
#post[forum_id] = #post_csv_order.inject({}) {|h,e| h[e[0]] = e[1]; h}
working code #2
#post[forum_id] = Hash[*#post_csv_order.flatten]
working code #3
#post[forum_id] ||= Hash[ #post_csv_order ] #requires 'require "backports"'

Resources