Assume a model Fruit with attributes name, price, and weight, and assume three arrays:
name = ["apple", "orange", "pear"]
price = [1.5, 1, 2]
weight = [130, 110, 120]
Is there a method that creates a new record in Rails comprising the i'th element of each array above?
Just out of curiosity:
name.
zip(price, weight).
map(&%i[name price weight].method(:zip)).
map(&:to_h).
map(&Fruit.method(:create))
There is no such a method but you iterate loop to add numbers objects inside Fruit as below,
name.length.times { |i| Fruit.create(name: name[i], price: price[i], weight: weight[i]) }
You can get an array of hashes by:
name.zip(price, weight).map { |a| Hash[[:name, :price, :weight].zip(a)] }
# [{:name=>"apple", :price=>1.5, :weight=>130}, {:name=>"orange", :price=>1, :weight=>110}, {:name=>"pear", :price=>2, :weight=>120}]
.zip merges arrays together. Hash[] is a special constructor method for hashes that takes an array of key/value pair arrays.
To create multiple records at once you can just pass an array of hashes to the create method:
Fruit.create(
name.zip(price, weight).map { |a| Hash[[:name, :price, :weight].zip(a)] }
)
Related
a little help with getting data out of a string.
Assuming I executed a sql query and now have a string(which set as hash on db):
"{\"users_associated\":{\"User:4\":6,\"User:22\":28,\"User:30\":36}}"
(Which stands for User:ID : User.display_id)
How can I get a substring the includes all users ids or all their display ids, so I'll have something like 4,22,30 or 6,22,36)?
Thanks!
It's common for data systems to return data in a serialized form, i.e. using data types that facilitate transmission of data. One of these serializable data types is String, which is how your JSON data object has been received.
The first step would be to de-serialize (or parse) this String into a Hash object using JSON.parse and tease out just the data value for key "users_associated".
your_string = "{\"users_associated\":{\"User:4\":6,\"User:22\":28,\"User:30\":36}}"
hash = JSON.parse(your_string)
data = hash["users_associated"]
#=> {"User:4":6, "User:22": 28, "User:30": 36}
Hash#keys gives you an array of a hash's keys.
Hash#values gives you an array of a hash's data values.
keys = data.keys
#=> ["User:4", "User:22", "User:30"]
values = data.values
#=> [6, 28, 36]
Array#join lets you string together the contents of an array with a defined separator, , in this case.
display_ids = keys.join(',')
#=> "6,28,36"
For the User IDs, you could Array#map every element of the values array to replace every string occurrence of "User:" with "", using String#gsub.
user_ids = values.map{|user_id| user_id.gsub("User:", "")}
#=> ["4", "22", "30"]
Then, in a similar way to display_ids, we can Array#join the contents of the user_ids array to a single string.
user_ids = user_ids.join(",")
#=> "4,22,30"
You can create two helper methods. I'm leaving return values as arrays because I assume you would need to iterate on them at some point and also converting the user id's to integers.
def extract_display_ids(json)
json['users_associated'].values
end
def extract_user_ids(some_data)
json['users_associated'].keys.map{ |key| key.split(':').last.to_i }
end
some_data = JSON.parse("{\"users_associated\":{\"User:4\":6,\"User:22\":28,\"User:30\":36}}")
extract_display_ids(some_data)
#=> [6, 28, 36]
extract_user_ids(some_data)
#=> [4, 22, 30]
If possible though, I would recommend trying to get a better data format:
{ users_associated:
[{ user_id : 4, display_id:6 }, { user_id : 4, display_id:6 }]
}
I wrote class for this. If you want, you can add it to your project and use it as follows:
require 'json'
class UserSubstringExtractor
def initialize(user_json_data)
#user_json_data = user_json_data
end
def display_ids
user_data.dig('users_associated').values
end
def user_ids
user_data.dig('users_associated').keys.map { |u| u.split(':').last.to_i }
end
private
def user_data
JSON.parse(#user_json_data)
end
end
user_json_data = '{"users_associated":{"User:4":6,"User:22":28,"User:30":36}}'
extractor = UserSubstringExtractor.new(user_json_data)
p extractor.display_ids
#=> [6, 28, 36]
p extractor.user_ids
#=> [4, 22, 30]
I have an array and it has many columns and I want to change one value of my one column.
My array is:
[
{
id: 1,
Districts: "Lakhisarai",
Area: 15.87,
Production: 67.77,
Productivity: 4271,
Year: 2015,
Area_Colour: "Red",
Production_Colour: "Orange",
Productivity_Colour: "Dark_Green",
created_at: "2018-07-24T11:24:13.000Z",
updated_at: "2018-07-24T11:24:13.000Z"
},
{
id: 29,
Districts: "Begusarai",
Area: 18.53,
Production: 29.35,
Productivity: 1584,
Year: 2015,
Area_Colour: "Red",
Production_Colour: "Red",
Productivity_Colour: "Orange",
created_at: "2018-07-24T11:24:13.000Z",
updated_at: "2018-07-24T11:24:13.000Z"
},
...
]
This is my sample array and I want my Productivity to be divided by 100 for that I am using one empty array and pushing these hashes to my array like:
j = []
b.map do |k|
if k.Productivity
u = k.Productivity/100
j.push({id: k.id, Productivity: u })
else
j.push({id: k.id, Productivity: k.Productivity })
end
Is there any simple way where I can generate this kind of array and reflect my changes to to one column. Is there any way where I don't need to push name of column one by one in push method.
I want to generate exact same array with one modification in productivity
let's say your array is e, then:
e.each { |item| item[:Productivity] = item[:Productivity]/100}
Example:
e = [{p: 12, d: 13}, {p:14, d:70}]
e.each { |item| item[:p] = item[:p]/10}
output: [{:p=>1, :d=>13}, {:p=>1, :d=>70}]
You could take help of map method here to create a new array from your original array, but with the mentioned changes.
ary.map do |elem|
h = elem.slice(:id)
h[:productivity] = elem[:Productivity] / 100 if elem[:Productivity]
h
end
=> [{:id=>1, :productivity=>42}, {:id=>29, :productivity=>15}]
Note, Hash#slice returns a new hash with only the key-value pairs for the keys passed in argument e.g. here, it returns { id: 1 } for first element.
Also, we are assigning the calculated productivity to the output only when it is set on original hash. Hence, the if condition there.
I have an array of objects that have an array as attribute. I want to concatenate these attributes. I'm doing this:
result = []
objects.each { |obj| result.concat(obj.attr) }
which works but looks bad. I tried
objects.reduce(:attr)
which does not work. It's a Rails app, and I want to concatenate related items into a single array. I want this:
[{
attr: [1,2]
},{
attr: [3,4]
}]
to turn into this:
[1,2,3,4]
You need to use Array#map :-
result = objects.map { |obj| obj.attr }
If you want the result array to be flattened :-
result = objects.flat_map { |obj| obj.attr }
I have a students array like this
[#<Student id: 2, admission_no: "2", gender: "m", blood_group: "A">,#<Student id: 3, admission_no: "3", gender: "m", blood_group: "A">]
I am getting this array via named_scope .... So is there any way to select only required attributes with named scope...
I need to delete admission_no and blood_group from this and return an array only with students id and gender.. How is it possible. Iam using rails2.3
named_scope_result.select('id, gender') will give you your desired result.
You want to have an array of hashes containing only the required fields, starting from your array.
Student.select('id, gender').find(:all)
will do if you want to consider all the Student objects in your database.
Starting from a generic Student array: students, you can achieve what you want by:
result = Array.new
students.each |s| do
data = { "id" => s.id, "gender" => s.gender }
result << data
end
do this
Student.select('id, gender').find(:all)
I have a hash with some key value pairs as below:
#level2 = #l2.inject(Hash.new(0)) { |hash,element|
hash[element] +=1
hash }
I perform some sorting on the hash based on the keys.
#level2 = #level2.sort_by { |x, _| x }.reverse
Now I assume that the sort_by gives me an Array of Arrays. I want to split this into 2 arrays such that my first array should contain all keys and second array should contain all values.
The hash#keys and hash#values are not accessible after sorting the hash. So that does not work in this case.
Regardless of how you make the hash it will will have a Hash#keys method and a Hash#values. They both return arrays that are just what you seem to want.
keys_array = #level2.keys
values_array = #level2.values
You could iterate over the array of arrays and add each element to a new array. This would keep the order of the elements.
keys_array = []
values_array = []
#level2.each do |key, value|
keys_array << key
values_array << value
end