Ruby Find by column and row in a multidimensional array [closed] - ruby-on-rails

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
So here is what my array looks like
[["Date", "Patient 1", "Patient 2", "Patient 3"],
["8/1/2014",0,0,0]
["8/2/2014",0,0,0]
["8/3/2014",0,0,0]]
I need to be able to find the index for "Patient 2" - "8/2/2014" which would of course be array[2][2] so that I can then change it's value from 0 to something else. How do I find that using the column and row names I've layed out?
Many thanks.

To find the row, you can use find and compare the value to the first element in each row:
matrix.find { |x| x[0] == "8/2/2014" }
# => ["8/2/2014", 0, 0, 0]
To find the column index, you can use index on the first array:
matrix[0].index("Patient 2")
# => 2
You can wrap it in a method:
def change_matrix(matrix, row, col, new_val)
matrix.find { |x| x[0] == row }[matrix[0].index(col)] = new_val
end
change_matrix(matrix, '8/2/2014', 'Patient 2', 5)
matrix
# => [["Date", "Patient 1", "Patient 2", "Patient 3"],
# ["8/1/2014", 0, 0, 0],
# ["8/2/2014", 0, 5, 0],
# ["8/3/2014", 0, 0, 0]]

You can do something like:
a = [["Date", "Patient 1", "Patient 2", "Patient 3"],["8/1/2014",0,0,0],["8/2/2014",0,0,0],["8/3/2014",0,0,0]]
b = a.transpose
print a[0][1] + " " + b[0][1]
Demo: http://runnable.com/U-oULwIJWFYZpeOx/transpose-for-ruby

Related

make a hash from active records [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
It could be have similar names and dates. but, take sum of count of similar dates.
#<ActiveRecord::Relation [Model name: "a", date: "20190703", count: 20>
#<ActiveRecord::Relation [Model name: "b", date: "20190702", count: 10>
#<ActiveRecord::Relation [Model name: "a", date: "20190702", count: nil>
#<ActiveRecord::Relation [Model name: "c", date: "20190703", count: 20>
#<ActiveRecord::Relation [Model name: "c", date: "20190702", count: 3>
#<ActiveRecord::Relation [Model name: "c", date: "20190702", count: 5> ...etc
Expected result would be like
{
:name=>"a", :data=>[{:date=>20190702, :count=>10}, {:date=>20190703, :count=>20}.....]
:name=>"b", :data=>[{:date=>20190702, :count=>10}, ...etc]
:name=>"c", :data=>[{:date=>20190702, :count=>8}, {:date=>20190703, :count=>20}, ..etc]
}
So given the fact that this is ActiveRecord data to begin with why not something like
data = Model.group(:name,:date).order(name: :asc, date: :asc).sum(:count)
data.each_with_object(Hash.new {|h,k| h[k] = []}) do |((name,date),count),obj|
obj[name] << {date: date, count: count}
end
This will produce:
{
"a"=>[{:date=>20190702, :count=>0}, {:date=>20190703, :count=>20}],
"b"=>[{:date=>20190702, :count=>10}],
"c"=>[{:date=>20190702, :count=>8}, {:date=>20190703, :count=>20}]
}
and all of the summing and grouping is placed on the SQL side of things (which is very efficient at aggregation)
You can have,
hash = users.group_by { |x| x.name }
hash.map do |name, model_data|
{
name: name,
data: model_data.group_by { |x| x[:date] }.values.map { |z| {date: z[0][:date], count: (z.inject(0) { |m,a| m += a[:count].to_i })} }
}
end
Output will be,
[
{:name=>"a", :data=>[{:date=>20190702, :count=>10}, {:date=>20190703, :count=>20}.....]},
{:name=>"b", :data=>[{:date=>20190702, :count=>10}, ...etc]},
{:name=>"c", :data=>[{:date=>20190702, :count=>8}, {:date=>20190703, :count=>20}, ..etc]}
]

Iterating a hash by comparing it with two separate arrays and arrive with a new hash desired result [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Array 1 = 7 elements
Array 2 = 7 elements
Hash = 7 elements
My requirement is to iterate through the each element in the hash with each element in array 1 and array 2 and come out with a new hash after applying the desired logic. The comparison is always going to be between the first element in hash against first element in array 1 and first element in array 2 and so on and so forth till I complete the list.
I am not even sure where and how to start so any help is appreciated to get me started
Is this what you are looking for?
arr1 = ['char', 'number', 'number', 'number', 'char', 'number', 'char']
arr2 = [6, '(7,0)','(15,0)','(5,0)',3,'(15,2)', 17]
h = { 'col1'=>'123456', 'col2'=>'0000111', 'col3'=>'000000002345',
'col4'=>'00023', 'col5'=>'abc', 'col6'=>'00000000000052367',
'col7'=>'0000000000321456' }
enum = arr1.zip(arr2).to_enum
#=> #<Enumerator: [["char", 6], ["number", "(7,0)"], ["number", "(15,0)"],
# ["number", "(5,0)"], ["char", 3], ["number", "(15,2)"], ["char", 17]]:each>
h.merge(h) { |*,v| [v].concat(enum.next) }
#=> {"col1"=>["123456", "char", 6], "col2"=>["0000111", "number", "(7,0)"],
# "col3"=>["000000002345", "number", "(15,0)"], "col4"=>["00023", "number", "(5,0)"],
# "col5"=>["abc", "char", 3], "col6"=>["00000000000052367", "number", "(15,2)"],
# "col7"=>["0000000000321456", "char", 17]}
This uses the form of Hash#merge that employs a block to determine the values of keys that are present in both hashes being merged, which here is all the keys of the hash.
You could use Array#zip to mix the hash and arrays :
hash = {
key1: :value1,
key2: :value2,
key3: :value3
}
array1 = %i(x1 x2 x3)
array2 = %i(y1 y2 y3)
new_hash = {}
hash.to_a.zip(array1, array2).each do |(key, value), element1, element2|
# logic with key, value, element1, and element2
# basic example :
new_hash[key] = [value, element1, element2]
end
p new_hash
# {:key1=>[:value1, :x1, :y1], :key2=>[:value2, :x2, :y2], :key3=>[:value3, :x3, :y3]}

Traverse JSON tree and in Ruby and format [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
my request returns any type of JSON. I would like to give a key to each attribute recursively in Ruby.
{
"name": "My name",
"age": 17,
"users": [
{
"name": "John Doe",
"colours": [
"blue",
"red"
],
"animals": [
{
"name": "Panthera"
}
]
}
]
}
It should traverse the tree and return:
[ 'name', 'age', 'users[]' 'users[]name', 'users[]colours', 'users[]animals', users[]animals[]name' ]
I can get top-level keys by calling Hash.keys but not sure how to traverse the tree and return custom key. Thanks for your help.
j = {"name":"My name","age":17,"users":[{"name":"John Doe","colours":["blue","red"],"animals":[{"name":"Panthera"}]}]}
a = []
j.keys.each do |key|
if key.class == Array
a << "#{key}[]"
else
a << key
end
end
a
This seems to achieve what you want. You were on the right track thinking recursively. I added comments to explain what's happening.
require 'json'
# Convert JSON to a ruby hash
j = JSON.parse('{"name":"My name","age":17,"users":[{"name":"John Doe","colours":["blue","red"],"animals":[{"name":"Panthera"}]}]}')
a = []
def make_array_from_hash_keys(array, hash, prefix = "")
# Iterate through the hash's key/value pairs
hash.each do |key, value|
# If the value is an array, we set a new prefix and add that to the main
# array. Then we iterate through this inner array to see if there are more
# hashes. If there are, call the parent method to generate more elements
# for the array, using the new prefix.
if value.class == Array
new_prefix = "#{prefix + key}[]"
array << new_prefix
hash[key].each do |array_value|
if array_value.class == Hash
# |= makes sure that the final array elements are unique
array |= make_array_from_hash_keys(array, array_value, new_prefix)
end
end
# If the value is not an array, simply add it to the main array with the
# necessary prefix
else
array << prefix + key
end
end
array
end
new_array = make_array_from_hash_keys(a, j)
puts new_array.inspect
# Gives us:
# ["name", "age", "users[]", "users[]name", "users[]colours[]", "users[]animals[]", "users[]animals[]name"]

Proper way to serialize json in database with rails [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Let's say that I have this kind of json.
In rails, I have three models:
Section that have many Questions
And Questions have one Answer
What is the proper way to save/update it in database ?
Thanks in advance for any help
{
"id": 1,
"section_name_fr": "Section1",
"section_number": 1,
"questions": [
{
"id": 2,
"question_fr": "Question12FR",
"input_type": "textarea",
"answer": {
"id": 1,
"answer": "Blabla"
}
},
{
"id": 4,
"question_fr": "Question14FR",
"input_type": "tel",
"answer": null
}
]
}
Lets say your example json is in a variable json. Then we can:
section_attributes = JSON.parse(json).symbolize_keys
# update section
section = Section.find_or_create_by id: section_attributes[:id]
section.update_attributes! section_attributes.slice(:section_name_fr, :section_number)
section_attributes[:questions].each do |question_attributes|
# update question
question = section.questions.find_or_create_by id: question_attributes[:id]
question.update_attributes! question_attributes.slice(:question_fr, :input_type)
# update answer
(question.answer || question.build_answer).update_attributes question_attributes[:answer].slice(:answer)
end
Note that this makes some assumptions about how you want the saving/updating to behave. For example, with questions, we try to find a question already in the given section with the given ID. If we can't find it, we create one. However, you may wish to search for any question with the given ID and associate with the section. In that case you would replace the update question lines with:
question = Question.find_or_create_by id: question_attributes[:id]
question.update_attributes! question_attributes.slice(:question_fr, :input_type).merge(section_id: section.id)
Also note that the use of slice on the attribute hashes is important for security reasons. In particular, it defines which attributes the json is allowed to modify.
First, you need to cast your json at hash ruby format:
json ='{
"id": 1,
"section_name_fr": "Section1",
"section_number": 1,
"questions": [
{
"id": 2,
"question_fr": "Question12FR",
"input_type": "textarea",
"answer": {
"id": 1,
"answer": "Blabla"
}
},
{
"id": 4,
"question_fr": "Question14FR",
"input_type": "tel",
"answer": null
}
]
}'
hash_ruby = JSON.parse(json)
Then
section = Section.find_or_create(id:hash_ruby["id"])
section.name_fr = hash_ruby["section_name_fr"]
section.number = hash_ruby["section_number"]
section.save
hash_ruby["questions"].each do |q|
new_question = Question.find_or_create(id:q["id"])
new_question.question_fr = q["question_fr"]
new_question.input_type = q["input_type"]
if !(q["answer"].nil?)
answer = Answer.find_or_create(id:q["anwser"]["id"])
answer.anwser = q["anwser"]["anwser"]
answer.save
new_question.answer=answer
end
new_question.section = section
new_question.save
end
I had suppose that the model Question contain a section foreign key and Question contain a anwser foreign key

Getting unique values and their count in a ruby 2-d array [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have a Ruby 2D Array, where each array has a row from a SQL query and its columns inside the subarray.
#mastertest = connection.execute("select code_ver from mastertest")
which might contain something like this:
#mastertest = [{"abc"} , {"abc"}, {"pqr"}, {"xyz"}, {"pqr"}, {"pqr"}]
Now, I want to form another 2D array which would give me just the rows which have a unique value of code_ver with their count.
Something like this:
#result = [{"abc", 2} , {"xyz", 1} , {"pqr", 3}]
#result = #mastertest.inject(Hash.new(0)) { |hash,element|
hash[element] +=1
hash
}
I think each_with_object is better way:
["abc" , "abc", "pqr", "xyz", "pqr", "pqr"].each_with_object({}) do |e, o|
o[e] ||= 0
o[e] += 1
end.to_a
#=> [["xyz", 1], ["abc", 2], ["pqr", 3]]
As Sawa said, your data are not valid Ruby objects. I assume you meant:
#mastertest = ["abc" , "abc", "pqr", "xyz", "pqr", "pqr"]
#result = #mastertest.inject({}) do |a, e|
a[e] ||= 0
a[e] += 1
a
end.to_a
#=> [["xyz", 1], ["abc", 2], ["pqr", 3]]

Resources