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 7 years ago.
Improve this question
I am trying to remove all whitespaces from an object's attribute that contains a given substring. For example, I have an object event and attributes: 4IP2, 3IP5, 2IP1. I would like to do the following:
event[4IP2].gsub(/\s+/, '')
in a generic manner, i.e.,
event[*IP*].gsub(/\s+/, '')
which should work for all attributes 4IP2, 3IP5, 2IP1. Appreciate any help.
Assuming, that event is a hash, here you go:
▶ event = { '4IP2' => 'a b c', '3GG5' => 'ffff f', '2IP1' => 'ggg ' }
▶ event.map { |k, v| [k, /IP/ =~ k ? v.delete(' ') : v] }.to_h
#⇒ { "2IP1" => "ggg", "3GG5" => "ffff f", "4IP2" => "abc" }
If you want to replace the attributes in-place:
event.each {|k,v| v.gsub!(/\s+/, '') if /IP/ =~ k}
Otherwise, to create a copy:
Hash[event.map {|k,v| [k, /IP/ =~ k ? v.gsub(/\s+/, '') : v]}]
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
In Ruby, what would be the best way to sort an array of objects by an order property that may or may not exist, and if it doesn't, then fall back to sorting based on a property named title?
Not sure if this is what you are after, but a quick solution could be:
arr = [{a:"never", b:"anna"}, {a:"always", b:"bob"}, {b:"colin"}, {b:"abe"}]
arr.sort_by! {|o| o[:a] ? o[:a] : o[:b] }
#=> [{:b=>"abe"}, {:a=>"always", :b=>"bob"}, {:b=>"colin"}, {:a=>"never", :b=>"anna"}]
Here's how to perform a sort with a fallback in Ruby:
Item = Struct.new(:order, :title)
items = [
Item.new(nil, "d"),
Item.new(nil, "b"),
Item.new(1, "a"),
Item.new(3, "c"),
Item.new(2, "e")
]
sorted_items = items.sort do |a, b|
if a.order && b.order
a.order <=> b.order
elsif a.order || b.order
# This prioritizes all items with an order
a.order ? -1 : 1
else
a.title.to_s <=> b.title.to_s
end
end
require 'awesome_print'
ap sorted_items
# [
# [0] {
# :order => 1,
# :title => "a"
# },
# [1] {
# :order => 2,
# :title => "e"
# },
# [2] {
# :order => 3,
# :title => "c"
# },
# [3] {
# :order => nil,
# :title => "b"
# },
# [4] {
# :order => nil,
# :title => "d"
# }
# ]
Let me also say that if you are fetching records from a database, then it would be better to do the sorting in your SQL query. If Item was an ActiveRecord model, you could do something like:
Item.order('order ASC NULLS LAST, title ASC')
(NULLS LAST can be used in Postgres, check out this answer for MySQL.)
If I understand you right here is how to do this:
arr1 = [{order: 1, title: 2},{title: 4},{order: 2, title: 1}]
arr2 = [{order: 1, title: 2},{order: 7, title: 4},{order: 2, title: 1}]
def sort_it prop1, prop2, ar
ar.map{|el| el[prop1]}.include?(nil) ?
ar.sort_by{|el| el[prop2]}
:
ar.sort_by{|el| el[prop1]}
end
p sort_it(:order, :title, arr1)
p sort_it(:order, :title, arr2)
Which gives:
#=> [{:order=>2, :title=>1}, {:order=>1, :title=>2}, {:title=>4}]
#=> [{:order=>1, :title=>2}, {:order=>2, :title=>1}, {:order=>7, :title=>4}]
So, the algorythm is simple: select all objects' properties (:order in our case) and if output temporary array contains at least one nil then sort by second given property, otherwise -- by first.
You could try
def sort_array(array)
sort_by_property_name = sort_by_property_present?(array, :order, :title)
array.sort_by { |ob| ob.public_send(sort_by_property_name) }
end
def sort_by_property_present?(array, primary_name, fallback_name)
array.all? { |ob| ob.respond_to?(name) } || return fallback_name
primary_name
end
Assuming you want to sort based on field/parameter that may or may not be present, I am assuming:
When the parameter is present sort by it.
When unavailable fall back to the next parameter.
Please review the following code that can sort an object array based on a number of fields, the system keeps falling back to the next field if the field is unavailable. Its developed with the assumption that the last field will definitely be present.
class CondtionalSort
def run(array: a, keys_to_order_by: keys)
array.sort do |e1, e2|
keys_to_order_by.each do |key|
break e1[key] <=> e2[key] if (e1.key?(key) && e2.key?(key))
end
end
end
end
ArrayTest = [{order: 1, title: 2},{title: 4},{order: 2, title: 1}]
ArrayTest_SORTED = [{:order=>1, :title=>2}, {:order=>2, :title=>1}, {:title=>4}]
sorter = CondtionalSort.new
sorter.run array: ArrayTest, keys_to_order_by: [:order, :title]
I just use an array as the sort_by:
# sample data:
Item = Struct.new(:property1, :property2, :property3)
collection = [Item.new("thing1", 3, 6), Item.new("thing1", 3, 1), Item.new("aaa", 1,1) ]
# sort
collection.sort_by{|item| [item.property1, item.property2, item.property3] }
# => [#<struct Item property1="aaa", property2=1, property3=1>,
#<struct Item property1="thing1", property2=3, property3=1>,
#<struct Item property1="thing1", property2=3, property3=6>]
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.
This post was edited and submitted for review 5 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I have an array of hashes:
my_array = [
{
:id => 1,
:name => "Bill"
},
{
:id => 2,
:name => "Joe"
},
{
:id => 3,
:name => "Bob"
}
]
How can I get an item passing the ID, for example, given 3 as the 'id' I'd like to get the hash: {"id": 3, "nome": "Bob"}.
UPDATE:
I discovered the answer, using the method .selec as follows:
my_array.select { |a| a[:id] == 1 }
What you have is a JSON string. You will need to parse it into an array of hashes first and then use Enumerable#find to get the item:
require 'json'
test = '[
{
"id": 1,
"nome": "Bill"
},
{
"id": 2,
"nome": "Joe"
},
{
"id": 3,
"nome": "Bob"
}
]'
# Parse into an array of hashes
hashes = JSON.parse(test)
foundItem = hashes.find { |item| item["id"] == 3}
puts foundItem
Since it looks like jSON you should parse as above if it is an actual array of Hashes you can do this
arr = [{"id" => 1,"nome"=> "Bill"},{"id"=> 2,"nome"=> "Joe"},{"id"=> 3,"nome"=> "Bob"}]
arr.select{|h| h["id"] == 3}
#=>[{"id"=> 3,"nome"=> "Bob"}]
This will return an Array of all matching Hash
To get a single value you can use
arr.select{|h| h["id"] == 3}.pop
#=>{"id"=> 3,"nome"=> "Bob"}
Which will return the last matching Hash Or as #KalmanHazins stated
arr.find{|h| h["id"] == 3}
#=>{"id"=> 3,"nome"=> "Bob"}
Which will return the first Hash that matches based on current order
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
I have this array of arrays:
[["abc", "123"], ["cde", "456"], ["cde", "674"]]
And I want this array of arrays arranged in this way:
{ "name": "test", "children": [ {"name": "abc", "children": [ {"name": "123"} ]}, {"name": "cde", "children": [ { "name": "456"},{"name": "674"} ]}]}
How can I make this transformation in ruby language?
Thanks in advance.
Try this
require 'json'
src_arr= [["abc", "123"], ["cde", "456"], ["cde", "674"]]
tmp = {} # to collect all common node first
src_arr.each do |arr|
if node = tmp[arr.first] # check if node exists
node['children'] << {'name' => arr.last} # append of exists
else
# add node if does not exists
tmp[arr.first] = {'name' => arr.first,'children' => [{'name' => arr.last}]}
end
end
tree = {'name' => 'test','children' => tmp.values}
puts tree
#=> {"name"=>"test", "children"=>[{"name"=>"abc", "children"=>[{"name"=>"123"}]}, {"name"=>"cde", "children"=>[{"name"=>"456"}, {"name"=>"674"}]}]}
puts JSON.generate(tree)
#=> {"name":"test","children":[{"name":"abc","children":[{"name":"123"}]},{"name":"cde","children":[{"name":"456"},{"name":"674"}]}]}
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
pry(main)> s = {:a =>2, :d=>'foo', :x => ' ', :n => true, :z => nil}
=> {:a=>2, :d=>"foo"}
pry(main)> s.each do |k,v| p k unless v.empty? end
NoMethodError: undefined method `length' for 2:Fixnum
I understand it happens because fixnum does not have empty methods. Then how to solve this problem in a slick way, no nasty finding data type first and then check it? I want to print those k where v has some value. Yes true is considered a value, but not bunch of spaces. For me "have value" means non-empty characters and boolean true.
With your updated comments, I think that is what you want.
s = {:a =>2, :d=>'foo', :x => ' ', :n => true, :z => nil}
s.each { |k,v| p(k) if !!v && !v.to_s.strip.empty? }
# :n
# :d
# :a
Quick solution:
s.each {|k,v| p k unless v.to_s.empty?}