Removing a hash from an array of hashes? - ruby-on-rails

h = {
:vehicle => [
[0] {
:make => "Honda",
:year => 2010
},
[1] {
:make => "Kia",
:year => 2014
},
[2] {
:make => "Saturn",
:year => 2005
}
]
}
I would like to remove {:make=>"Kia", :year=>2014} so that h is:
h = {
:vehicle => [
[0] {
:make => "Honda",
:year => 2010
},
[1] {
:make => "Saturn",
:year => 2005
}
]
}
I tried:
h[:vehicle].delete_if{ |_,v| v == "Kia" }
#=> does nothing
h.delete_if{ |_,v| v == "Kia" }
#=> does nothing
h[:vehicle].tap { |_,v| v.delete("Kia") }
#=> does nothing
h.delete("Kia")
#=> nil
h[:vehicle].delete("Kia")
#=> nil
Here's where I'm getting a headache:
h[:vehicle].include?("Kia")
#=> false
h[:vehicle][1]
#=> {:make=>"Kia", :year=>2014}
h[:vehicle][1].include?("Kia")
#=> false
Thanks for the help.

h[:vehicle].delete_if { |h| h[:make] == 'Kia' }
Will return a copy of h with Kia removed. Note that although its a somewhat strange way to do it, your first example does work for me. Remember that you have to look at the returned value to see the result - delete_if does not modify the original hash.

Related

get rid of "duplicates" in nested hash

I have a nested hash:
given = {
"AA" => {
:GE => nil,
"GE" => "successful",
:GR => nil,
:ZG => nil,
"ZG" => "successful",
},
"BB" => {
:MM => nil,
"MM" => "successful",
:GR => nil,
:ZZ => nil,
"ZZ" => "successful",
}
}
and my goal is to transform it into a new hash without the duplicates eg. :GE/"GE" and :ZG/"ZG" and so on.
goal = {
"AA" => {
:GE => "successful",
:GR => nil,
:ZG => "successful",
},
"BB" => {
:MM => "successful",
:GR => nil,
:ZZ => "successful",
}
}
My attempt is with Rails method index_by
given.map do |key, value|
value.index_by {|r| value[r]}
end
Or with
given.each { |key,value| temp_hash = {} (value.each { |va| va[0].each { |k,v| temp_hash|key| << val }}) given_hash[k.to_sym] = temp_hash if given.has_key?(k.to_sym)}
But I'm kind of stuck. Any help is greatly appreciated!
I'm assuming that in the case of { :GE => nil, "GE" => "successful" }, you want to use the first truthy value ("successful") and make sure the key is a symbol:
result = given.transform_values do |inner_hsh|
inner_hsh.group_by do |k,v|
k.to_sym
end.transform_values do |key_vals|
key_vals.to_h.values.find(&:itself)
end
end
Assuming that #max's assumption is correct, and also that the order of the keys in inner hashes is not important, here is another way to produce the desired return value.
given.each_with_object({}) do |(k,v),h|
h[k] = v.sort_by { |_,w| w.nil? ? 1 : 0 }.uniq { |m,_| m.to_s }.to_h
end
#=> {"AA"=>{"GE"=>"successful", "ZG"=>"successful", :GR=>nil},
# "BB"=>{"MM"=>"successful", "ZZ"=>"successful", :GR=>nil}}
See Array#uniq, particularly the sentence, "self is traversed in order, and the first occurrence is kept.".
For
k = "AA"
v = { :GE=>nil, "GE"=>"successful", :GR=>nil, :ZG=>nil, "ZG"=>"successful" }
we compute
a = v.sort_by { |_,w| w.nil? ? 1 : 0 }
#=> [["GE", "successful"], ["ZG", "successful"],
# [:GE, nil], [:GR, nil], [:ZG, nil]]
b = a.uniq { |m,_| m.to_s }
#=> [["GE", "successful"], ["ZG", "successful"], [:GR, nil]]
because "GE" precedes :GE and "ZG" precedes :ZG. Lastly,
h[k] = b.to_h
#=> {"GE"=>"successful", "ZG"=>"successful", :GR=>nil}

Merge two hashes in ruby

I have two collections of hashes
and_filters = [{:filter=>:brand, :value=>"Fila"}, {:filter=>:brand, :value=>"Adidas"}]
or_filters = [{:filter=>:gender, :value=>"Hombre"}]
and i need make like the following struct
:_or => [
{ :_and => [
{:gender => "Hombre"},
{:brand => "Adidas"}]
},
{ :_and => [
{:gender=>"Hombre"},
{:brand=>"Fila"}]
}
]
For this i did
query[:_or] = []
or_filters.each do |or_f|
query[:_or] << {
:_and => [
and_filters.map do |and_f|
{and_f[:filter] => and_f[:value]}
end
{ or_f[:filter] => or_f[:value] }
]
}
end
but an error Expected: { shows in code. Apparently the second loop is badly syntactically
It's not pretty, but I believe this gives the desired results:
{_or: or_filters.each_with_object([]) do |or_filter, or_filter_ary|
or_filter_hsh = {or_filter[:filter] => or_filter[:value]}
and_filters.each do |and_filter|
and_filter_hsh = {and_filter[:filter] => and_filter[:value]}
or_filter_ary << {_and: [or_filter_hsh, and_filter_hsh]}
end
end
}
Which gives:
{:_or => [
{ :_and => [
{:gender=>"Hombre"},
{:brand=>"Fila"}
]},
{ :_and => [
{:gender=>"Hombre"},
{:brand=>"Adidas"}
]}
]}
It looks like you want every combination of the given and_filters with the given or_filters. In that case, and assuming you don't care about order (:gender before :brand vs. the other way around) Array#product is your friend:
result = {
_or: and_filters.product(or_filters).map do |a|
{ _and: a.map {|filter:, value:| { filter => value }} }
end
}
# => {
# :_or => [
# {:_and => [{:brand=>"Fila"}, {:gender=>"Hombre"}]},
# {:_and => [{:brand=>"Adidas"}, {:gender => "Hombre"}]}
# ]
# }
See it in action on repl.it: https://repl.it/#jrunning/HorizontalDirectCharmap
Thats what i was looking for
query = {}
query[:_or] = or_filters.map do |or_f|
and_filters_aux = and_filters.dup
and_filters_aux << or_f
{ :_and => and_filters_aux.map{|hsh| {hsh[:filter] => hsh[:value]} } }
end
https://repl.it/repls/ShyLateClients

Grabbing a specific hash in an array that meets a specific criteria

I have a huge array full of a bunch of hashes. What I need to do is single out one index hash from the array that meets a specific criteria. (doing this due to an rspec test, but having trouble singling out one of them)
My array is like this
[
{
"name" => "jon doe",
"team" => "team2",
"price" => 2000,
"eligibility_settings" => {}
},
{
"name" => "jonny doe",
"team" => "team1",
"value" => 2000,
"eligibility_settings" => {
"player_gender" => male,
"player_max_age" => 26,
"player_min_age" => 23,
"established_union_only" => true
}
},
{
"name" => "jonni doe",
"team" => "team3",
"price" => 2000,
"eligibility_settings" => {}
},
]
I need to single out the second one, based on its eligibility settings. I just took three of them from my array, have lots more, so simple active record methods like (hash.second) won't work in this instance.
I've tried things like
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
However when I try this, I get a nil response. (which is odd)
I've also looked into using the ruby detect method, which hasn't gotten me anywhere either
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Would anybody have any idea what to do with this one?
Notes
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Is is players or Players ?
Why is it plural?
If you can call map on team, it probably should be plural
Why do you convert to a hash?
eligibility_settings? isn't a key in your hash. eligibility_settings is
eligibility_settings can be a hash, but it cannot be true
If you want to check if it isn't empty, use !h['eligibility_settings'].empty?
Possible solution
You could use :
data = [
{
'name' => 'jon doe',
'team' => 'team2',
'price' => 2000,
'eligibility_settings' => {}
},
{
'name' => 'jonny doe',
'team' => 'team1',
'value' => 2000,
'eligibility_settings' => {
'player_gender' => 'male',
'player_max_age' => 26,
'player_min_age' => 23,
'established_union_only' => true
}
},
{
'name' => 'jonni doe',
'team' => 'team3',
'price' => 2000,
'eligibility_settings' => {}
}
]
p data.find { |h| !h['eligibility_settings'].empty? }
# {"name"=>"jonny doe", "team"=>"team1", "value"=>2000, "eligibility_settings"=>{"player_gender"=>"male", "player_max_age"=>26, "player_min_age"=>23, "established_union_only"=>true}}
If h['eligibility_settings'] can be nil, you can use :
data.find { |h| !h['eligibility_settings'].blank? }
or
data.find { |h| h['eligibility_settings'].present? }

In Rails, what is the best way to compact a hash into a nested hash

Say I have this:
[
{ :user_id => 1, :search_id => a},
{ :user_id => 1, :search_id => b},
{ :user_id => 2, :search_id => c},
{ :user_id => 2, :search_id => d}
]
and I want to end up with:
[
{ :user_id => 1, :search_id => [a,b]},
{ :user_id => 2, :search_id => [c,d]}
]
What is the best way to do that?
Very strange requirement indeed. Anyway
[ { :user_id => 1, :search_id => "a"},
{ :user_id => 1, :search_id => "b"},
{ :user_id => 2, :search_id => "c"},
{ :user_id => 2, :search_id => "d"} ] \
.map{ |h| h.values_at(:user_id, :search_id) } \
.group_by(&:first) \
.map{ |k, v| { :user_id => k, :search_id => v.map(&:last) } }
array.group_by{|x| x[:user_id] }.values.map do |val|
{ user_id: val.first[:user_id],
search_id: val.inject([]){|me, el| me << el[:search_id]} }
end
First off, I think the cleaner output structure here is to allow the user IDs to be the hash keys and the list of search IDs to be the values:
{
1 => [a, b],
2 => [c, d]
}
There might be a clever way using Rails helpers to get this structure, but it's not too bad to do it manually, either:
output = {}
input.each do |row|
key = row[:user_id]
value = row[:search_id]
output[key] ||= []
output[key] << value
end
I agree with Matchus representation of the data and just want to suggest a shorter version for it (input being the initial array).
input.each.with_object(Hash.new {|h,k| h[k] = []}) do |k,o|
o[k[:user_id]] << k[:search_id]
end
EDIT: this is Ruby > 1.9
input.inject({}) do
|m, h| (m[h[:user_id]] ||= []) << h[:search_id]; m
end.inject([]) { |m, (k, v)| m << { :user_id => k, :search_id => v }; m }

Ruby how to sort hash of hashes?

I have that deep Hash of hashes:
my_hash = {
:category_1 => {
:solution_1 => { :order => 1 },
:solution_2 => { :order => 2 }
},
:category_2 => {
:solution_3 => { :order => 3 },
:solution_4 => { :order => 4 }
}
}
I want to sort :solution_* hashes under :category_* hashes by key :order. Any suggestions?
(fixed)
Let's say you have the following hash of people to ages:
people = {
:fred => { :name => "Fred", :age => 23 },
:joan => { :name => "Joan", :age => 18 },
:pete => { :name => "Pete", :age => 54 }
}
use sort_by to get where we want to go:
people.sort_by { |k, v| v[:age] }
# => [[:joan, {:name=>"Joan", :age=>18}],
[:fred, {:name=>"Fred", :age=>23}],
[:pete, {:name=>"Pete", :age=>54}]]
Ok, you didn't specify your question, so I'm assuming you want one layer removed. I changed the starting hash a bit to actually see if the sorting works:
my_hash = {
:category_1 => {
:solution_1 => { :order => 2 },
:solution_2 => { :order => 3 }
},
:category_2 => {
:solution_3 => { :order => 4 },
:solution_4 => { :order => 1 }
}
}
Hash[my_hash.inject({}) { |h, (k, v)| h.merge(v) }.sort_by { |k,v| v[:order] }]
#=> {:solution_4=>{:order=>1}, :solution_1=>{:order=>2}, :solution_2=>{:order=>3}, :solution_3=>{:order=>4}}
EDIT:
Taking into account your clarification (and still starting from the modified unsorted hash I posted above):
sorted = my_hash.inject({}) do |h, (k, v)|
h[k] = Hash[v.sort_by { |k1, v1| v1[:order] }]
h
end
#=> {:category_1=>{:solution_1=>{:order=>2}, :solution_2=>{:order=>3}}, :category_2=>{:solution_4=>{:order=>1}, :solution_3=>{:order=>4}}}

Resources