无法理解为什么我的Itertools.combinations_with_replacement实现无法正常工作

时间:2014-01-30 21:12:09

标签: python combinations itertools

无法弄清楚为什么我的代码不会输出itertools.combinations_with_replacement的正确结果(如果是某些小值)。

from itertools import combinations_with_replacement
menu = []
with open("menu.txt") as f:
    for line in f:
        budget = float(line.split("$")[-1])           # extract the budget
        break
    for line in f:                      
        itemName = line.split(",")[0]
        itemPrice = float(line.split("$")[-1])
        menu.append([itemName,itemPrice])
def shorten_list(menu):   # function to filter out items where price > budget
    i=0;                                
    for item in menu:
        if item[-1] > budget:
            del menu[i]
        i = i + 1
    return menu
shorten_list(menu)          #call to shorten_list function
for item in menu:
    item[-1] = int(item[-1]*100)    # cast to int to avoid floating point imprecision errors

budget = int(budget *100)     # cast to int to avoid floating point imprecision errors
flag = 0       # set a flag = 0 to check if solutions will be found
num_comb = 1
comb = [c for i in range(len(menu)+1) for c in combinations_with_replacement(menu, i)]      # outputs iterator with all possible combinations
print("\n")
for e in comb:
    if sum(l[1] for l in e) == budget:                  # filters out only the combinations that == our budget
        print ("Combination_with_R number " + str(num_comb)  + " is:") 
        print ([l[0] for l in e])                       # print only the item name
        print ("\n")
        num_comb += 1 
        flag = 1                        # if an solutions found we set flag = 1
    if flag == 0:           # if no solutions found, flag = 0 has not changed 
    print ("There is no combination of dishes that will equal your budget... Leave the change as tip! \n\n ")

我对代码的问题主要是当我需要一个组合来重复某个菜单项来创建一顿饭时。例如,如果我们有菜单项面包,$ 1.00和budget = 18,那么组合['bread', 'bread','bread','bread'..... n=18]应该是18个面包。或者,如果项目是ketchup_packet,$ 0.10和budget = 18,则还应该有['ketchup_packet',............ n = 180]的组合。假设menu.txt采用以下格式:

$18.00
mixed fruit,$2.15
french fries,$2.75
side salad,$3.35
hot wings,$3.55
mozzarella sticks,$4.20
sampler plate,$5.80
pasta3,$5.05
salad,$3.25
pasta10,$10.10
pasta1,$2.65
TESTER,$1.20

由于某些原因,使用此menu.txt,它不会输出['TESTER', 'TESTER',..... N =15]

的组合

但如果menu.txt是:

$12.00
mixed fruit,$2.15
french fries,$2.75
side salad,$3.35
hot wings,$3.55
mozzarella sticks,$4.20
sampler plate,$5.80
pasta3,$5.05
salad,$3.25
pasta10,$10.10
pasta1,$2.65
TESTER,$1.20

它会正确输出所有组合,包括['TESTER','TESTER',..... n = 12]

它也适用于

$12.00
mixed fruit,$2.15
    french fries,$2.75
    side salad,$3.35
    hot wings,$3.55
    mozzarella sticks,$4.20
    sampler plate,$5.80
    pasta3,$5.05
    salad,$3.25
    pasta10,$10.10
    pasta1,$2.65
    TESTER,$0.01

但不是!无法理解为什么。

2 个答案:

答案 0 :(得分:0)

comb = [c for i in range(len(menu)+1) for c in combinations_with_replacement(menu, i)]

这允许多个项目最多等于菜单中的事物数量。它永远不会比菜单有更多的汉堡包。

答案 1 :(得分:0)

我清理了代码格式,考虑了一堆实用函数,并将其转换为线性编程问题。看看你的想法:

from decimal import Decimal

def get_name(s):
    return s.split(',')[0]

def get_price(s):
    return Decimal(s.split('$')[-1])

def get_menu(fname):
    with open(fname) as inf:
        budget = get_price(inf.next())
        items = [(get_name(line), get_price(line)) for line in inf]
    return budget, items

def integer_linear_solver(coefficients, total, index=None):
    """
    Given coefficients [c0, c1, ... cN] and total,
    generate all integer solutions to the equation
        s0*c0 + s1*c1 + ... + sN*cN == total
    and return as [s0, s1, ... sN]
    """
    if index is None:
        # Start at the end and work back
        # (this avoids having to repeatedly slice coefficients)
        index = len(coefficients) - 1

    c = coefficients[index]
    max_s = total // c

    if index:  # more coefficients available - recurse
        for s in range(max_s + 1):    # [0 .. max_s]
            for sol in integer_linear_solver(coefficients, total - s*c, index-1):
                yield sol + [s]
    else: # last coefficient
        if not(total % c):
            # no remainder -> exact solution found
            yield [max_s]

def print_sol(coeffs, labels):
    items = ('{0} {1}'.format(c, l) for c,l in zip(coeffs, labels) if c > 0)
    print(', '.join(items))

def main():
    budget,items = get_menu('menu.txt')
    names,prices = zip(*items)

    solutions = 0
    for sol in integer_linear_solver(prices, budget):
        print_sol(sol, names)
        solutions += 1

    if solutions:
        print('{} solutions found'.format(solutions))
    else:
        print("There is no combination of dishes that will equal your budget.")

if __name__=="__main__":
    main()

针对您的第一个示例菜单运行,它会显示

2 side salad, 2 hot wings, 1 mozzarella sticks
2 french fries, 2 side salad, 1 sampler plate
1 mixed fruit, 3 side salad, 1 sampler plate
...
1 mixed fruit, 1 pasta1, 11 TESTER
15 TESTER
109 solutions found