I have an array of Relation class on ruby on rails which I call using #relations
Example:
#relations[0] {id => 13, name => 'Giovanni', age => 50}
#relations[1] {id => 25, name => 'Astolf', age => 27}
#relations[2] {id => 5, name => 'Bob', age => 37}
I want to sort this array based on name. It'll as listed below:
#relations[0] {id => 25, name => 'Astolf', age => 27}
#relations[1] {id => 5, name => 'Bob', age => 37}
#relations[2] {id => 13, name => 'Giovanni', age => 50}
How can I do it?
very simple:
#relations = [{:id => 13, :name => 'Giovanni', :age => 50},
{:id => 25, :name => 'Astolf', :age => 27},
{:id => 5, :name => 'Bob', :age => 37}]
#relations.sort_by{|e| e[:name]}
# => [{:id=>25, :name=>"Astolf", :age=>27},
# {:id=>5, :name=>"Bob", :age=>37},
# {:id=>13, :name=>"Giovanni", :age=>50}]
Related
I am using Ruby on Rails application. I want to combine 2 array of hashes with hash and to result in array of hashes.
Inputs:
first_array_of_hash = [{:name => "John", :age => 34, :mode => "nullable"},{:name => "Rose", :age => 30, :mode => "nullable"}]
second_hash = {:field_name => "", :field_age => nil, :field_nullable => false, :field_default => ""}
I want my result to be like below
result = [{:field_name => "John", :field_age => 34, :field_nullable => true, :field_default => ""},{:field_name => "Rose", :field_age => 30, :field_nullable => true, :field_default => ""}]
You can use a regular Array#map for this:
first_array_of_hash = [{:name => "John", :age => 34, :nullable => 'yes'},{:name => "Rose", :age => 30, :nullable => 'no'}]
second_hash = {:field_name => "", :field_age => nil, :field_nullable => false, :field_default => ""}
def transform(object)
{
field_name: object[:name],
field_age: object[:age],
field_nullable: object[:mode] == 'nullable'
}
end
result = first_array_of_hash.map do |object|
second_hash.merge(transform(object))
end
puts result
currently, I have a hash like this:
#lg = {
"Latin East Group" => [
{:id => 2, :name => "HONGKONG"},
{:id => 3, :name => "NINGBO, ZHEJIANG"},
{:id => 4, :name => "SINGAPORE"},
{:id => 5, :name => "LARCHMONT, NY"},
{:id => 6, :name => "CHICAGO, IL"},
{:id => 7, :name => "HAIPHONG"},
{:id => 8, :name => "DANANG"},
{:id => 9, :name => "HANOI"},
{:id => 10, :name => "MARSEILLE"},
{:id => 11, :name => "LONDON"},
{:id => 12, :name => "EDINBURGH"},
{:id => 13, :name => "AMSTERDAM"},
{:id => 14, :name => "HOCHIMINH"},
{:id => 15, :name => "SHANGHAI"}
],
"Latin West Group" => [],
"Others" => [
{:id => 16, :name => "Brazil" },
{:id => 17, :name => "Mexico" },
{:id => 18, :name => "Columbia"}
]
}
Now, I am using select2 with my form, and I wanna create a dropdown menu from that hash instance variable. I want the keys of the hash will be the optgroups, and the option values are gonna be the name sin the hash like Singapore, Brazil... Therefore, I am wondering what is the correct syntax for it. Currently, this is my code:
_form_body.haml:
%div.col-md-8
= f.grouped_collection_select :origin_locations, #lg, #lg.keys, #lg.values, {:selected => f.options[:origin_locations]}, {class: 'form-control select2-multiple origin_locations', :multiple => true}
pricing_histories_controller.rb:
def load_location_groups
#lg = {}
location_groups = LocationGroup.all.includes(:locations).each { |group|
#lg[group.name]= group.locations.map{|l| {id: l.id,name: l.name}}
}
# location_groups.each_with_index do |location_group, index|
arr = Location.where("id NOT IN (SELECT DISTINCT(location_id) FROM location_group_assignments)").pluck(:id,:name)
#location_groups = {}
#lg["Others"] = arr.map{ |e| {id: e.first, name: e.last}}
end
I will get the error:
ActionView::Template::Error (["Latin East Group", "Latin West Group",
"Others"] is not a symbol nor a string)
So, I am wondering what I am doing wrong here. Any suggestions would be appreciated. Thanks and have a nice day.
I am trying to replicate nested attributes in my model. The params that are passed when I create a new object through the GUI are:
tenant_script_call"=>{"name"=>"TEST_01", "script_id"=>"12", "script_call_arguments_attributes"=>{"0"=>{"script_argument_id"=>"16", "argumentable_id"=>"43", "argumentable_type"=>"AstQueue"}, "1"=>{"script_argument_id"=>"17", "value"=>""}, "2"=>{"script_argument_id"=>"18", "value"=>""}, "3"=>{"script_argument_id"=>"19", "argumentable_id"=>"250", "argumentable_type"=>"Playlist"}}}, "commit"=>"Submit"}
I am trying to automate this in my controller. I have tried:
TenantScriptCall.new(:name => "TEST_01", :location_id => location.id, :script_id => 12, :script_call_arguments_attributes [:script_argument_id => 16, :argumentable_id => self.id, :argumentable_type => "AstQueue", [:script_argument_id => 17, :value => "", [:script_argument_id => 18, :value => "", [:script_argument_id => 19, :argumentable_id => Playlist.last.id, :argumentable_type => "Playlist"]]]])
and
TenantScriptCall.new(:name => "TEST_01", :location_id => location.id, :script_id => 12, :script_call_arguments_attributes [:script_argument_id => 16, :argumentable_id => self.id, :argumentable_type => "AstQueue"] [:script_argument_id => 17, :value => ""] [:script_argument_id => 18, :value => ""] [:script_argument_id => 19, :argumentable_id => Playlist.last.id, :argumentable_type => "Playlist"])
As well as a few different variations. Can someone point me in the right direction or share some knowledge/wisdom please?
First of all, your calls are a bit flawed. What are location and self in this context?
Your model definition should be something like this:
class TenantScriptCall < ActiveRecord::Base
has_many :script_call_arguments
accepts_nested_attributes_for :script_call_arguments
end
And then, if you want to pass input from the UI:
TenantScriptCall.new(params[:tenant_script_call])
should work.
Ultimately you should filter the input with permit, like #hemali pointed out.
You can create a private method
def tenant_params
params.require(:tenant).permit(:column_names)
end
And now whenever u want to create. You just do this.
ModelName.create(tenant_params)
This did it for me:
def auto_create_destination_for_ast_queue(location)
auto_destination_name_queue = AstQueue.last.name.split(/-/)[0]
TenantScriptCall.new(:name => auto_destination_name_queue,
:location_id => location.id,
:script_id => 12,
:script_call_arguments_attributes => [{:script_argument_id => 16,
:argumentable_id => AstQueue.last.id,
:argumentable_type => "AstQueue"},
{:script_argument_id => 19,
:argumentable_id => 3,
:argumentable_type => "Playlist"}]).save
end
I want to output an array of hashes with the name being unique to all hashes. How would I go about doing this using ruby?
This is my input:
input = [{:name => "Kutty", :score => 2, :some_key => 'value', ...},
{:name => "Kutty", :score => 4, :some_key => 'value', ...},
{:name => "Baba", :score => 5, :some_key => 'value', ...}]
I want the output to look like this:
output = [{:name => "Kutty", :score => 4, :some_key => 'value', ...},
{:name => "Baba", :score => 5, :some_key => 'value', ...}]
To just remove duplicates based on :name, simply try;
output = input.uniq { |x| x[:name] }
Demo here.
Edit: Since you added a sorting requirement in the comments, here's how to select the entry with the highest score for every name if you're using Rails, I see you already got an answer for "standard" Ruby above;
output = input.group_by { |x| x[:name] }
.map {|x,y|y.max_by {|x|x[:score]}}
A little explanation may be in order; the first line groups the entries by name so that each name gets its own array of entries. The second line goes through the groups, name by name, and maps each name group to the entry with the highest score.
Demo here.
input = [{:name => "Kutty", :score => 2, :some_key => 'value'},{:name => "Kutty", :score => 4, :some_key => 'value'},{:name => "Baba", :score => 5, :some_key => 'value'}]
p input.uniq { |e| e[:name] }
The above solution works for ruby > 1.9, for older versions of ruby you could use something along these lines:
input = [{:name => "Kutty", :score => 2, :some_key => 'value'},{:name => "Kutty", :score => 4, :some_key => 'value'},{:name => "Baba", :score => 5, :some_key => 'value'}]
unames = []
new_input = input.delete_if { |e|
if unames.include?(e[:name])
true
else
unames << e[:name]
false
end
}
p new_input
Try this solution..
input = [{:name => "Kutty", :score => 2, :some_key => 'value'},
{:name => "Kutty", :score => 4, :some_key => 'value'},
{:name => "Baba", :score => 5, :some_key => 'value'}]
a = []
output = []
input.collect do |i|
input.delete(i) if !a.include?(i[:name])
output << i if !a.include?(i[:name])
a << i[:name] if !a.include?(i[:name])
end
output = [{:some_key=>"value", :name=>"Kutty", :score=>2},
{:some_key=>"value", :name=>"Baba", :score=>5}]
UPDATED
output = {}
input.each do |e|
ref = output[e[:name]]
if ref && ref[:score] > e[:score]
#nothing
else
output[e[:name]] = e
end
end
check output:
puts output.values
input.uniq{|hash| hash[:name]}
From a model that returns all the values from a table, how would I convert that to a hash of name value pairs
{column_value => column_value}
e.g.
[{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
to (specifying :id and :name)
{'first' => 1, 'second' => 2, 'third' => 3}
You can do it in one line with inject:
a = [{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
a.inject({}) { |sum, h| sum.merge({ h[:name] => h[:id]}) }
# => {"third" => 3, "second" => 2, "first" => 1}
The following approach is reasonably compact, yet still readable:
def join_rows(rows, key_column, value_column)
result = {}
rows.each { |row| result[row[key_column]] = row[value_column] }
result
end
Usage:
>> rows = [{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
>> join_rows(rows, :name, :id)
=> {"third"=>3, "second"=>2, "first"=>1}
Or, if you want a one-liner:
>> rows.inject({}) { |result, row| result.update(row[:name] => row[:id]) }
=> {"third"=>3, "second"=>2, "first"=>1}
o = Hash.new
a = [{:id => 1, :name => 'first'}, {:id => 2, :name => 'second'}, {:id => 3, :name => 'third'}]
a.each {|h| o[h[:name]] = h[:id] }
puts o #{'third' => 3, 'second' => 2, 'first' => 1}