我必须找到订单金额等于或大于给定数量的订单列表。例如,
order # amount
o1 100
o2 50
o3 90
o4 150
o5 20
o6 30
o7 50
如果我需要找到订单金额等于300或大于300的订单,那么我应该得到o5,o6,o2,o7,o3,o1或o1,o4,o3。如果订单是最小到最大或最大到最小,则无关紧要。我怎么能以最小的方式做到这一点?我知道第一步是排序。我可以使用数组求和来获得所有元素的总和但是如何获得加起来或者只是大于给定数字的元素?
我使用Ruby on Rails和Oracle作为db。
答案 0 :(得分:1)
你的问题其实很简单。首先,通过减少数量来订购订单:
orders = [["o1", 100], ["o2", 50], ["o3", 90], ["o4", 150],
["o5", 20], ["o6", 30], ["o7", 50]]
sorted_orders = orders.sort_by(&:last).reverse
#=> [["o4", 150], ["o1", 100], ["o3", 90], ["o7", 50],
# ["o2", 50], ["o6", 30], ["o5", 20]]
假设:
min_req = 300
首先看看是否可以通过使用所有项目来实现min_req
:
orders.reduce(0) { |tot,(_,qty)| tot+qty } < min_req
#=> false
如果返回true
我们就完成了:因为数量都是非负数,我们就会计算出数量子集之和的最大可能值。
然后只需按排序顺序获取项目,直到数量总和至少为min_req
:
tot = 0
sorted_orders.take_while { |_,qty| tot < min_req && tot += qty }
#=> [["o4", 150], ["o1", 100], ["o3", 90]]
我们可以将它包装在一个方法中:
def smallest_combination(orders, min_req)
return nil if orders.reduce(0) { |tot,(_,qty)| tot+qty } < min_req
tot = 0
orders.sort_by(&:last)
.reverse
.take_while { |_,qty| tot < min_req && tot += qty }
end
smallest_combination(orders, 300)
#=> [["o4", 150], ["o1", 100], ["o3", 90]]
smallest_combination(orders, 400)
#=> [["o4", 150], ["o1", 100], ["o3", 90], ["o7", 50], ["o2", 50]]
smallest_combination(orders, 500)
#=> nil