# Example 1
People = ["Terry", "Merry"]
Fruit = ["Apple","Grape","Peach"]
# Possible solutions:
[
{"Terry"=>"Apple","Merry"=>"Grape"},
{"Terry"=>"Apple","Merry"=>"Peach"},
{"Terry"=>"Grape","Merry"=>"Apple"},
{"Terry"=>"Grape","Merry"=>"Peach"},
{"Terry"=>"Peach","Merry"=>"Apple"},
{"Terry"=>"Peach","Merry"=>"Grape"},
]
# Example 2
People = ["Terry", "Merry", "Perry"]
Fruit = ["Apple","Grape"]
# Possible solutions:
[
{"Terry"=>"Apple","Merry"=>"Grape","Perry"=>nil},
{"Terry"=>"Apple","Merry"=>nil,"Perry"=>"Grape"},
{"Terry"=>"Grape","Merry"=>"Apple","Perry"=>nil},
{"Terry"=>"Grape","Merry"=>nil,"Perry"=>"Apple"},
{"Terry"=>nil,"Merry"=>"Apple","Perry"=>"Grape"},
{"Terry"=>nil,"Merry"=>"Grape","Perry"=>"Apple"},
]
Stuck trying to solve this recursively (necessary for this exercise, though let me know if you don't think recursion is possible).
I feel like basically I start by assigning a random person a fruit, and then add that to all possible solutions that arise from the smaller subset of assigning remaining people remaining fruit.
E.g., for Example 1, I assign Terry an Apple, and then aggregate that with the remaining possible options of what Merry can get (either Grape or Peach).
Then just repeat changing up the fruit assigned to the first random person (e.g., with Terry getting Grape then Peach, in Example 1).
I feel like this sounds so straightforward but I'm struggling.
It can be done recursively as follows.
def hmmm(people, fruit)
adj_fruit = fruit + [nil]*([people.size-fruit.size, 0].max)
recurse(adj_fruit).map { |a| people.zip(a).to_h }
end
def recurse(fruit_left, fruit_selected = [])
return [fruit_selected + fruit_left] if fruit_left.size == 1
fruit_left.each_with_object([]) do |f,a|
recurse(fruit_left - [f], fruit_selected + [f]).each { |e| a << e }
end
end
hmmm(["Terry", "Merry"], ["Apple", "Grape", "Peach"])
#=> [{"Terry"=>"Apple", "Merry"=>"Grape"}, {"Terry"=>"Apple", "Merry"=>"Peach"},
# {"Terry"=>"Grape", "Merry"=>"Apple"}, {"Terry"=>"Grape", "Merry"=>"Peach"},
# {"Terry"=>"Peach", "Merry"=>"Apple"}, {"Terry"=>"Peach", "Merry"=>"Grape"}]
Here adj_fruit #=> ["Apple", "Grape", "Peach"]
hmmm(["Terry", "Merry", "Perry"], ["Apple", "Grape"])
#=> [{"Terry"=>"Apple", "Merry"=>"Grape", "Perry"=>nil},
# {"Terry"=>"Apple", "Merry"=>nil, "Perry"=>"Grape"},
# {"Terry"=>"Grape", "Merry"=>"Apple", "Perry"=>nil},
# {"Terry"=>"Grape", "Merry"=>nil, "Perry"=>"Apple"},
# {"Terry"=>nil, "Merry"=>"Apple", "Perry"=>"Grape"},
# {"Terry"=>nil, "Merry"=>"Grape", "Perry"=>"Apple"}]
Here adj_fruit #=> ["Apple", "Grape", nil].
We can see map's receiver in hmmm by removing .map { |a| people.zip(a).to_h } from its last line.
def hmmm(people, fruit)
adj_fruit = fruit + [nil]*([people.size-fruit.size, 0].max)
recurse(adj_fruit)
end
hmmm(["Terry", "Merry"], ["Apple","Grape","Peach"])
#=> [["Apple", "Grape", "Peach"], ["Apple", "Peach", "Grape"],
# ["Grape", "Apple", "Peach"], ["Grape", "Peach", "Apple"],
# ["Peach", "Apple", "Grape"], ["Peach", "Grape", "Apple"]]
A more conventional solution, such as the one following, would not employ recursion.
def hmmm(people, fruit)
(fruit + [nil]*[people.size - fruit.size, 0].max).
permutation(people.size).
map { |a| people.zip(a).to_h }
end
This produces the same return values as those shown above for the recursive solution.
See Array#permutation and Enumerable#zip.
If len(people) <= len(fruit), then you can use
for pieces in itertools.permutations(fruit, len(people)):
assign the pieces of fruit to the people in order
If len(people) > len(fruit), then use
for eaters in itertools.permutations(people, len(fruit))
assign the eaters to the fruit in order, and the others get nothing
I don't know how to combine the two separate cases into a single case
I now see that this was supposed to be solve recursively. Misread the original.
Let's look the possibilities for
assignment(people, fruit):
If len(people) == 0, then you're done, with the empty solution. (Not to be confused with no solution.)
If len(fruit) == 0, then no one gets any fruit. Again, this is an actual solution.
If len(people) <= len(fruit), then the first person gets some piece of fruit, appended onto all possible results of the remainder of the people getting the remainder of the fruit.
If len(people) > len(fruit), then either the first person does or doesn't get a piece of fruit, and recursively the rest of the people get whatever's left.
It's left as an exercise to you how to code this.
For anyone's future reference, this was my answer using recursion.
NOTE that "nil" overcounts; since "nil" is treated as a unique entry, the code reads {"Terry"=>"apple","Merry"=>"nil","Perry"=>"nil"} and {"Terry"=>"apple","Perry"=>"nil","Merry"=>"nil"} as 2 distinct solutions. I did not investigate further because this isn't super realistic for the exercise that this is a part of.
I also didn't investigate further for same reason, but using string "nil" versus nil yielded different results
def pure5(people, fruit, solution = [])
people_count = people.size
fruit_count = fruit.size
diff = people_count - fruit_count
diff.times { fruit << "nil" } if diff > 0
people.each do |p|
fruit.each do |f|
if people.size == 1
obj = {}
obj[p] = f
solution << obj
else
partial_solution = pure5(people - [p], fruit - [f])
partial_solution.each do |s|
s[p] = f
end
solution = solution + partial_solution
end
end
return solution
end
end
I have to remove the 'Other' Category from the array, which is originally sorted alphabetically, and just make it the last index. I created this little helper but believe there could be a faster way of accomplishing this.
The array is something like this [#<Category id: 17, title: "Books">, #<Category id: 18, title: "Children's Clothing">,
Here is what I've done. It works. Although, I was wonder if theres a more efficient way.
<%
#options = []
#other_option = []
#free_item_options.each do |category|
if category.title.downcase == "other"
#other_option << category
else
#options << category
end
end
#options << #other_option[0]
%>
In cases like this, I usually reach for multi-parameter sorting.
#free_item_options.sort_by do |option|
[
option.title.casecmp?('other') ? 1 : 0,
option.title,
]
end
"Other" category will have 1 and will sort last. Everything else will have 0 and will sort between themselves by ascending title.
Another approach is to just use SQL.
#free_item_options = Category.select("categories.*, (LOWER(title) = 'other') as is_other").order('is_other', :title).to_a
There is Enumerable#partition which is designed to split a collection up in two partitions.
#other_option, #options = #free_item_options.partition { |category| category.title.casecmp?('other') }
#options.concat(#other_options)
If you are certain there is a maximum of one "other" category (which seems to be the case based upon #options << #other_option[0]). You could also use find_index in combination with delete_at and <<. find_index stops iterating upon the first match.
index = #free_item_options.find_index { |category| category.title.casecmp?('other') }
#free_item_options << #free_item_options.delete_at(index) if index
Keep in mind the above does mutate #free_item_options.
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.
How can I combine these two arrays in to a hash. They may be of equal sizes or not.
#status_array = ["ready", "required", "processing", "approval", "live"]
#part_milestones = [#<Milestone id: 657707, data_type: "ready">, #<Milestone id: 657708, data_type: "required">, #<Milestone id: 657709, data_type: "approval">]
They are sorted already. I just need the hash to deal with the "blanks" properly like so:
{"ready"=>#<Milestone id: 657707, data_type: "ready">, "required"=>#<Milestone id: 657708, data_type: "required">, "processing"=>nil, "approval"=>#<Milestone id: 657709, data_type: "approval">, "live"=>nil}
The cleanest way I know to do this is:
hash = #status_array.inject({}) do |result_hash, status|
result_hash[status] = #part_milestones.select { |milestone| milestone.data_type == status }.first
result_hash
end
You can use zip to merge the arrays into two dimensional and then use the following to convert into hash
Hash[#status_array.zip(#part_milestones)]
Documentation for Hash[]
UPDATE:
just realized that its not a one to one mapping
hash = {}
#status_array.each do |status|
hash[status] = #part_milestone.find{|milestone| milestone.data_type == status}
end
#part_milestones.sort_by &:data_type should do the trick
I have a list of key value pairs like this.
PERSON_SUMMARY = {
first_names: %w(Mike Tim Jim kevin Alan Sara John Sammy t'Renée),
last_names: %w(Robinson Jackson Fox Terry Ali Brits Tyson Willis-St.\ Paul),
offenses: [
{ offense_name:'Speeding',
penalties: [
{ penalty_name: 'Prison', severity: 'Medium' },
{ penalty_name: 'Ticket', severity: 'Low' }
]
},
{ offense_name:'Shoplifting',
penalties: [
{ penalty_name: 'Prison', severity: 'Medium' },
{ penalty_name: 'Fine', severity: 'Low' }
]
}
]
}
I want to store and print only offense_name,**penalty_name** and severity one by one , but I am not able to get the right syntax.
Here is what I have tried so far:
PERSON_SUMMARY[:offenses].each do |offense|
offense_name = offense[:offense_name]
offense[:penalties].each do |penalty|
penalty_name = penalty[:penalty_name]
severity_val = penalty[:severity]
end
end
EDIT: Eventually I need to insert it into the database table through this function:
PersonOffense.where(person_id: person.id).first_or_create(
name: offense_name,
penalty: penalty_name ,
severity: severity_val
end
But I notice an issue, there are multiple penalty names above. Not sure how to insert them.
For example,
I need to insert offense_name twice in my table so that there are 2 entries in the table.
Speeding Prison Medium
Speeding Ticket Low
EDIT: I like Jesse's answer below. How can I use it to insert it in the same order to my method above (inserting offense_name,penalty_name and severity with the result of the answer given below by Jesse.
Rather than just using each, if you map over the offenses, and then flatten them in the end, you'll get what you want:
offenses = PERSON_SUMMARY[:offenses].map do |offense|
offense[:penalties].map do |penalty|
penalty.merge(name: offense[:offense_name])
end
end.flatten
=> [{:penalty_name=>"Prison", :severity=>"Medium", :name=>"Speeding"}, {:penalty_name=>"Ticket", :severity=>"Low", :name=>"Speeding"}, {:penalty_name=>"Prison", :severity=>"Medium", :name=>"Shoplifting"}, {:penalty_name=>"Fine", :severity=>"Low", :name=>"Shoplifting"}]
UPDATE
In ruby, the following is a hash, and you already have a hash
So you can just loop through your new array and create your PersonOffense:
offenses.each do |hash|
PersonOffense.where(person_id: person.id).first_or_create( hash )
end