Similar Array items but not exact ruby - ruby-on-rails

I would like to see if I can check 2 arrays with similar values against each other and return the items that are different between the 2. However I have items that have similar names and I would want those to be excluded as well.
Example:
pantry = ["apples", "chedder cheese mild", "flour", "salt"]
recipe = ["bacon", "chedder cheese sharp", "flour", "chocolate"]
#=> desired return ["apples","bacon", "chocolate", "salt"]
What I get using pantry - recipe #=> ["apples", "bacon", "chocolate", "salt", "cheddar cheese mild"]

If we assume that "similar" means multi word strings where all but the last word are the same...
pantry = ["apples", "chedder cheese mild", "flour", "salt"]
recipe = ["bacon", "chedder cheese sharp", "flour", "chocolate"]
result = (pantry + recipe).group_by{|x| x.slice(0,(x.index(/[\s][^\s]+\z/) || x.size))}
result = result.values.select{|x|x.size == 1}.flatten.sort
=> ["apples", "bacon", "chocolate", "salt"]

Related

Find various ways of allocating fruit to people

# 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

How to remove repeated string values from a list

This is a continuation of a previous question.
I have a fixed list in Lua which I am reassigning values for
local a = {"apple", "pear", "orange", "kiwi", "tomato"}
local map = {
apple = "RD",
pear = "GR",
orange = "OG",
kiwi = "GR",
tomato = "RD",
banana = "YL",
}
colours = {}
for index = 1, #a do
table.insert(colours,map[a[index]or "OT")
end
Now I would either like to edit the existing script, or add some new script, to remove any repeated values.
My end result should be a table (colours) with no repeated values or empty strings, but I can't seem to think of a neat way to do this!
If it's not possible (or really messy) my second option would be to count the number unique values in the table.
If you don't want to run over the entire table every time you add an element you can simply create a second table where you remember which colours have been listed yet.
Simply use the colour as key.
local a = {"apple", "pear", "orange", "kiwi", "tomato"}
local map = {
apple = "RD",
pear = "GR",
orange = "OG",
kiwi = "GR",
tomato = "RD",
banana = "YL",
}
local listedColours = {}
local colours = {}
for _,colour in pairs(a) do
colour = map[colour] or "OT"
if not listedColours[colour] then
table.insert(colours, colour)
listedColors[colour] = true
end
end
Solution i suggest: add to table function contains
table.contains = function(t, value)
for index = 1, #t do
if t[index] == value then
return index
end
end
end
so problem with having only unique colours can be solved like:
for index = 1, #a do
local colour = map[a[index]] or "OT"
if not table.contains(colours, colour) then
table.insert(colours, colour)
end
end
I consider it pretty neat

Lua string.gsub inside string.gmatch?

I've created this simple example script to output a list of foods. If the food is a fruit then the color of the fruit will be displayed as well. The issue I'm having is in dealing with the irregular pluralization of 'strawberries.'
fruits = {apple = "green", orange = "orange", stawberry = "red"}
foods = {"potatoes", "apples", "strawberries", "carrots", "crab-apples"}
for _, food in ipairs(foods) do
for fruit, fruit_colour in pairs(fruits) do
duplicate = false
if (string.match(food, "^"..fruit) or string.match((string.gsub(food, "ies", "y")), "^"..fruit)) and not(duplicate) then -- this is where the troubles is!
print(food.." = "..fruit_colour)
duplicate = true
break
end
end
if not(duplicate) then
print(food)
end
end
Right now the program outputs:
potatoes
apples = green
strawberries
carrots
crab-apples
What I want is:
potatoes
apples = green
strawberries = red
carrots
crab-apples
I can't figure out why this doesn't work like I want it to!
Well for one thing, you miss-spelled strawberry here:
fruits = {apple = "green", orange = "orange", stawberry = "red"}
You can also work with lua tables as sets, which means that nested loop searching for duplicates is unnecessary. It can be simplified to something like:
fruits = {apple = "green", orange = "orange", strawberry = "red"}
foods = {"potatoes", "apples", "strawberries", "carrots", "crab-apples"}
function singular(word)
return word:gsub("(%a+)ies$", "%1y"):gsub("(%a+)s$", "%1")
end
for _, food in ipairs(foods) do
local single_fruit = singular(food)
if fruits[single_fruit] then
print(food .. " = " .. fruits[single_fruit])
else
print(food)
end
end
stawberry should be strawberry. The loop changes strawberries to strawberry and then tries to match strawberry against ^stawberry, but the typo causes it not to match.

finding list of constant in an array

I have a list of constant:
FRUITS = [MANGO, BANANA, ORANGE, GUAVA]
and array which is superset of this constant, like
EDIBLE_ITEMS = [APPLE, CORN, MANGO, RICE, ORANGE, PAPAYA, LITCHI, RICE]
So now I need to test if any of the elements from FRUITS matches EDIBLE_ITEMS then call a function.
Any help will be appreciated. Thanks
Using Array#&:
FRUITS = ['MANGO', 'BANANA', 'ORANGE', 'GUAVA']
EDIBLE_ITEMS = ['APPLE', 'CORN', 'MANGO', 'RICE', 'ORANGE', 'PAPAYA', 'LITCHI', 'RICE']
(FRUITS & EDIBLE_ITEMS).any?
# => true
Do as below using Enumerable#any? :
EDIBLE_ITEMS = %w[APPLE, CORN, MANGO, RICE, ORANGE, PAPAYA, LITCHI, RICE]
FRUITS = %w[MANGO, BANANA, ORANGE, GUAVA]
FRUITS.any? { |item| EDIBLE_ITEMS.include? item } # => true

How can I get the number of instances of a value in a Rails array?

Say I have an array like this:
["white", "red", "blue", "red", "white", "green", "red", "blue", "white", "orange"]
I want to go through the array and create a new array containing each individual color and the amount of times it appeared in the original array.
So, in the new array it would report that "white" appeared 3 times, "blue" appeared 2 times and so on...
How should I go about doing this?
better return a hash...
def arr_times(arr)
arr.inject(Hash.new(0)) { |h,n| h[n] += 1; h }
end
counts = Hash.new(0)
colors.each do |color|
counts[color] += 1
end
result = {}
hash = array.group_by{|item| item}.each{|key, values| result[key] = values.size}
p result
I see you tagged the question with ruby-on-rails.
If this is a database model/column (e.g., User model with color attribute) you should be doing the computation in the DB:
User.count(:all,:group=>:color).sort_by {|arr| -arr[1]}

Resources