I have incoming json request in this format:
{ "id":"1", "fields":{"attr1":"value1", "attr2":"value2", ... "attrN":"valueN"}}
I need to decompose json string in my controller to this:
id: 1
attr1: value1
attr2: value2
...
attrN: valueN
How can I do this? I use Rails 4. Thanks
if you wanna add entire json hash to array, you can do something like this.
arr = Array.new
json_arr = { "id":"1", "fields":{"attr1":"value1", "attr2":"value2", ... "attrN":"valueN"}}
json_arr.each do |arr|
temp_hash = Hash.new
temp_hash = arr
arr.push(arr)
end
I am not sure about your requirement.
Related
I have a Ruby array of students. Student class has attributes id, name and age.
students = [
{id:"id1",name:"name1",age:"age1"},
{id:"id2",name:"name2",age:"age2"},
{id:"id3",name:"name3",age:"age3"}
]
I want to create a JSON key value object from this array as follows.
json_object = {id1:name1, id2:name2, id3:name3}
input = [ {id:"id1",name:"name1",age:"age1"},
{id:"id2",name:"name2",age:"age2"},
{id:"id3",name:"name3",age:"age3"}]
require 'json'
JSON.dump(input.map { |hash| [hash[:id], hash[:name]] }.to_h)
#⇒ '{"id1":"name1","id2":"name2","id3":"name3"}'
Give this a go:
students = [
{id:"id1",name:"name1",age:"age1"},
{id:"id2",name:"name2",age:"age2"},
{id:"id3",name:"name3",age:"age3"}
]
json_object = students.each_with_object({}) do |hsh, returning|
returning[hsh[:id]] = hsh[:name]
end.to_json
In console:
puts json_object
=> {"id1":"name1","id2":"name2","id3":"name3"}
Your data is all identical, but if you wanted to generate a hash that took the value of students[n][:id] as keys and students[n][:name] as values you could do this:
student_ids_to_names = students.each_with_object({}) do |student, memo|
memo[student[:id]] = student[:name]
end
For your data, you'd end up with only one entry as the students are identical: { "id1" => "name1" }. If the data were different each key would be unique on :id.
Once you have a hash, you can call json_object = students_ids_to_names.to_json to get a JSON string.
Given an array of hashes, I want to create a method that returns a hash where the keys are the unique values of the hashes in the array.
For example, I'd like to take
[
{foo: 'bar', baz: 'bang'},
{foo: 'rab', baz: 'bang'},
{foo: 'bizz', baz: 'buzz'}
]
and return
{
foo: ['bar', 'rab', 'bizz'],
baz: ['bang', 'buzz']
}
I am currently accomplishing this using:
def my_fantastic_method(data)
response_data = { foo: [], baz: []}
data.each { |data|
data.attributes.each { |key, value|
response_data[key.to_sym] << value
}
}
response_data.each { |key, value| response_data[key] = response_data[key].uniq }
response_data
end
Is there a more elegant way of doing this? Thanks!
Your current approach is already pretty good; I don't see much room for improvement. I would write it like this:
def my_fantastic_method(data_list)
data_list.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |data, result|
data.attributes.each do |key, value|
result[key.to_sym] << value
end
end
end
By setting a default value on each hash value, I have eliminated the need to explicitly declare foo: [], bar: [].
By using each_with_object, I have eliminated the need to declare a local variable and explicitly return it at the end.
By using Set, there is no need to call uniq on the final result. This requires less code, and is more performant. However, if you really want the final result to be a mapping to Arrays rather than Sets, then you would need to call to_a on each value at the end of the method.
I have used different variable names for data_list and data. Call these whatever you like, but it's typically considered bad practice to shadow outer variables.
Here are a couple of one-liners. (I'm pretty sure #eiko was being facetious, but I'm proving him correct)
This one reads well and is easy to follow (caveat: requires Ruby 2.4+ for transform_values):
array.flat_map(&:entries).group_by(&:first).transform_values{|v| v.map(&:last).uniq}
Here's another, using the block form of merge to specify an alternate merge method, which in this case is combining the values into a uniq array:
array.reduce{|h, el| h.merge(el){|k, old, new| ([old]+[new]).flatten.uniq}}
You already have a pretty good answer, but I felt golfy and so here is a shorter one:
def the_combiner(a)
hash = {}
a.map(&:to_a).flatten(1).each do |k,v|
hash[k] ||= []
hash[k].push(v)
end
hash
end
Try this:
array.flat_map(&:entries)
.group_by(&:first)
.map{|k,v| {k => v.map(&:last)} }
OR
a.inject({}) {|old_h, new_h|
new_h.each_pair {|k, v|
old_h.key?(k) ? old_h[k] << v : old_h[k]=[v]};
old_h}
If, as in the example, all hashes have the same keys, you could do as follows.
arr = [{ foo: 'bar', baz: 'bang' },
{ foo: 'rab', baz: 'bang' },
{ foo: 'bizz', baz: 'buzz' }]
keys = arr.first.keys
keys.zip(arr.map { |h| h.values_at(*keys) }.transpose.map(&:uniq)).to_h
#=> {:foo=>["bar", "rab", "bizz"], :baz=>["bang", "buzz"]}
The steps are as follows.
keys = arr.first.keys
#=> [:foo, :baz]
a = arr.map { |h| h.values_at(*keys) }
#=> [["bar", "bang"], ["rab", "bang"], ["bizz", "buzz"]]
b = a.transpose
#=> [["bar", "rab", "bizz"], ["bang", "bang", "buzz"]]
c = b.map(&:uniq)
#=> [["bar", "rab", "bizz"], ["bang", "buzz"]]
d = c.to_h
#=> <array of hashes shown above>
I now have a JSON string:
[{"id":1,"name":"good","created_at":"2014-07-28T19:45:50.440Z","updated_at":"2014-07-28T19:45:50.440Z"},{"id":2,"name":"better","created_at":"2014-07-28T19:45:50.447Z","updated_at":"2014-07-28T19:45:50.447Z"},{"id":3,"name":"best","created_at":"2014-07-28T19:45:50.449Z","updated_at":"2014-07-28T19:45:50.449Z"}]
And I have an array:
id = ["1", "3"]
I want to check for the common IDs and print the associated name. For the above example I want my output to be:
["good","best"]
I want the output preferably to be an array. Is there a easy way to do this? I have been writing too much code to get this done and feel it should be easily done. Any suggestions?
# initiate json string
json = %q([{"id":1,"name":"good","created_at":"2014-07-28T19:45:50.440Z","updated_at":"2014-07-28T19:45:50.440Z"},{"id":2,"name":"better","created_at":"2014-07-28T19:45:50.447Z","updated_at":"2014-07-28T19:45:50.447Z"},{"id":3,"name":"best","created_at":"2014-07-28T19:45:50.449Z","updated_at":"2014-07-28T19:45:50.449Z"}])
ids = ["1", "3"]
JSON.parse(json).select{|x| ids.include? x["id"].to_s}.map{|x| x["name"]}
#=> ["good", "best"]
require 'json'
def pluck(json, ids)
json_parsed = JSON.parse(json)
json_parsed.select do |obj|
ids.include?(obj['id'])
end
.map do |obj|
obj['name']
end
end
# usage
json = '[{"id":1,"name":"good","created_at":"2014-07-28T19:45:50.440Z","updated_at":"2014-07-28T19:45:50.440Z"},{"id":2,"name":"better","created_at":"2014-07-28T19:45:50.447Z","updated_at":"2014-07-28T19:45:50.447Z"},{"id":3,"name":"best","created_at":"2014-07-28T19:45:50.449Z","updated_at":"2014-07-28T19:45:50.449Z"}]'
ids = [1, 3]
pluck(json, ids)
in you controller can do this:
def method_name
render json: Model.pluck(:name).to_json
end
Hi i'am new in ruby and i want to get a Hash with string in keys and an Array in value, like this :
Hash = new HashMap
for (issue :is)
Hash.add(is.user_name)
if(hash.contains(is.user_name)) then
hash.value.add(is)
end
end
to get a result like this :
{"jane"[issue123,issue234,issue345]; "mike" [issue333,issue444,issue555]; "Alain" [issue876,issue987,issue356] }
jane have [issue123,issue234,issue345]
thanks
Something like below:
result = Hash.new { |hash, key| hash[key] = [] }
issues.each do |issue|
result[issue.user_name].push issue
end
I'm trying to pass an array through Net::HTTP to a ruby
def send_p
x = Net::HTTP.post_form(URI.parse('http://example_domain/example'), to_send)
render text: x
end
def to_send
{
param_a: "foo",
param_b: [1,2,3]
}
end
but when check the params in http://example_domain/example is getting me
{
"param_a"=>"foo",
"param_b"=>"3",
"action"=>"my_method",
"controller"=>"my_controller"
}
what can I do to receive the array in the proper way: [1,2,3]
Try using HTTParty:
x = HTTParty.post(URI.parse('http://example_domain/example'), to_send)
You can convert the array to string and then do the inverse when getting the params from the response.
Convert to String before to send it
param_b: [1,2,3].to_s
You will receive exactly as you sent it
"param_b"=>"[1,2,3]"
Convert it back to Array
eval(params[:param_b])
# => [1, 2, 3]