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
Related
I have long list of values in the inner_value field from which I want only some values
I have array in this format:
hash_array = [
{
"array_value" => 1,
"inner_value" => [
{"iwantthis" => "forFirst"},
{"iwantthis2" => "forFirst2"},
{"Idontwantthis" => "some value"},
{"iwantthis3" => "forFirst3"},
{"Idontwantthis2" => "some value"},
{"Idontwantthis3" => "some value"},
{"Idontwantthis4" => "some value"},
{"Idontwantthis5" => "some value"},
{"Idontwantthis6" => "some value"},
]
},
{
"array_value" => 2,
"inner_value" => [
{"iwantthis" => "forSecond"},
{"Idontwantthis" => "some value"},
{"iwantthis3" => "forSecond3"},
{"iwantthis2" => "forSecond2"},
{"Idontwantthis2" => "some value"},
{"Idontwantthis3" => "some value"},
{"Idontwantthis4" => "some value"},
{"Idontwantthis5" => "some value"},
{"Idontwantthis6" => "some value"},
]
},
]
Desired Output:
[
{
"array_value" => 1,
"inner_value" => [
{"iwantthis" => "forFirst"},
{"iwantthis2" => "forFirst2"},
{"iwantthis3" => "forFirst3"}
]
},
{
"array_value" => 2,
"inner_value" => [
{"iwantthis" => "forSecond"},
{"iwantthis2" => "forSecond2"},
{"iwantthis3" => "forSecond3"}
]
},
]
I have tried using running loop in this but its too much costly.
So I tried something like this:
hash_array.select { |x| x["inner_value"].select {|y| !y["iwantthis"].nil? } }
but this ain't working either..
Note:Order/Sort does not matter
Your aim is not to select, you have to modify the input:
hash_array.map { |hash| hash['inner_value'] = hash['inner_value'].first }
#=> [
# {
# "array_value"=>1,
# "inner_value"=> {
# "iwantthis"=>"forFirst"
# }
# },
# {
# "array_value"=>2,
# "inner_value"=> {
# "iwantthis"=>"forSecond"
# }
# }
# ]
Here you'd basically change the value of whole hash['inner_value'] to what you want.
To do this with known key:
hash_array.map do |hash|
hash['inner_value'] = hash['inner_value'].find { |hash| hash['iwantthis'] }
end # `iwantthis` is the key, that can change
For multiple keys:
keys = %w(iwantthis Idontwantthis)
hash_array.map do |hash|
hash['inner_value'] = keys.flat_map do |key|
hash['inner_value'].select {|hash| hash if hash[key] }
end
end
#=> [{"array_value"=>1, "inner_value"=>[{"iwantthis"=>"forFirst"}, {"Idontwantthis"=>"some value"}]}, {"array_value"=>2, "inner_value"=>[{"iwantthis"=>"forSecond"}, {"Idontwantthis"=>"some value"}]}]
you can use map
hash_array.map{|k| {"array_value" => k['array_value'], 'inner_value' => k['inner_value'][0]} }
#=> [{"array_value"=>1, "inner_value"=>{"iwantthis"=>"forFirst"}}, {"array_value"=>2, "inner_value"=>{"iwantthis"=>"forSecond"}}]
I have this situation:
skeleton =
{
"timeline" =>
{
"data" => []
}
}
template =
{
"A" => "",
"B" => "",
"C" => "",
}
From the controller I make a query which returns me an array of hashes:
#cdr = Cdr.select("start, end, clid")
then I iterate over the array and set the "template" hash fields and in the last step I append this hash to an array which belongs to "skeleton" hash:
#cdr.each do |cdr|
template["A"] = cdr.start
template["B"] = cdr.end
template["C"] = cdr.clid
skeleton["timeline"]["data"] << template
end
so to expected result is:
skeleton =
{
"timeline" =>
{
"data" => [
{
"A" => "sample1",
"B" => "sample2",
"C" => "sample3",
},
{
"A" => "sample4",
"B" => "sample5",
"C" => "sample6",
}
]
}
}
but the real result I'm getting is:
skeleton =
{
"timeline" =>
{
"data" => [
{
"A" => "sample1",
"B" => "sample2",
"C" => "sample3",
},
{
"A" => "sample1",
"B" => "sample2",
"C" => "sample3",
}
]
}
}
all entries in the array contain same data. Why?
Try creating a new template array through each cycle through. I don't think you can change the value of the key while it is being used as a key.
#cdr.each do |cdr|
temp_inst = template.clone
temp_inst["A"] = cdr.start
temp_inst["B"] = cdr.end
temp_inst["C"] = cdr.clid
skeleton["timeline"]["data"] << temp_inst
end
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}}}
I have an array like this:
['one','three','two','four']
I have a array of hash like this:
[{'three' => {..some data here..} }, {'two' => {..some data here..} }, {:total => some_total }] # etc...
I want to sort the array of hashes by the first array. I know I can do:
array_of_hashes.sort_by{|k,v| k.to_s} to sort them and it will sort by the key
( and the .to_s to convert :total to a string )
How can I make this happen?
Edit:
I was incorrect about how this is setup, it is actually like this:
{'one' => {:total => 1, :some_other_value => 5}, 'two' => {:total => 2, :some_other_value => 3} }
If I need to put this in a new question, just let me know and I will do that.
Thank you
similar to ctcherry answer, but using sort_by.
sort_arr = ['one','three','two','four']
hash_arr = [{'three' => {..some data here..} }, {'two' => {..some data here..} }]
hash_arr.sort_by { |h| sort_arr.index(h.keys.first) }
The index method of Array is your friend in this case:
sort_list = ['one','three','two','four']
data_list = [{'three' => { :test => 3 } }, {'two' => { :test => 2 } }, {'one' => { :test => 1 } }, {'four' => { :test => 4 } }]
puts data_list.sort { |a,b|
sort_list.index(a.keys.first) <=> sort_list.index(b.keys.first)
}.inspect
Resulting in, the same order as the source array:
[{"one"=>{:test=>1}}, {"three"=>{:test=>3}}, {"two"=>{:test=>2}}, {"four"=>{:test=>4}}]
I am using Ruby on Rails 3 and I would like to "trasform" the following array so that I can use my custom logic to access its data.
This is the original array from which I have to build a new one
[
{
"account" => {
"id" => 45,
"name" => "Test_name",
"..." => ..."
}
},
{
"other" => {
"sub_other" => {...}
}
}
]
I would like to trasform the above array so that I can do in my controller something like
array_name[45]
# => {
"name" => "Test_name",
"..." => ..."
}
but only for the account hashs. The other hash should remain untouched.
How can I proceed to build the new array?
If I understand your requirements correctly, I think you are better off constructing a hash from account id to account data. Perhaps something like this will work:
arr = [
{
"account" => {
"id" => 45,
"name" => "Test_name",
"..." => "..."
}
},
{
"other" => {
"sub_other" => "..."
}
}
]
account_hashes = arr.select {|item| item.keys.first == "account"}
answer = account_hashes.inject({}) do |acc, item|
acc[item["account"].delete("id")] = item["account"]
acc
end