如何创建所有唯一组合的列表,同时为每个组合保留一个总列?

How to create list of all unique combinations while keeping a total column for each combination?

我正在尝试找到所有可能的独特组合来制作三明治。我还想知道每个三明治要多少钱。我有 3 组两个清单,一个清单是关于商品的,第二个是关于商品价格的。

bread = ['italian', 'wheat', 'honey oat']
bprice = [1, 2, 3]
meat = ['roastbeef', 'ham', 'turkey', 'steak']
mprice = [3, 1, 2, 4]
vegetable = ['lettuce', 'onions', 'tomatoes', 'pickles']
vprice = [1, 4, 2, 3]

我试图找到所有唯一的可能组合,但我还想要每个组合的总数。该组合应包含一种面包、一种肉和两种不同的蔬菜。例如:

输出:

          Combinations                Total
italian, ham, onions, pickles           9
italian, turkey, onions, pickles       ...
wheat, ham, onions, pickles            ...

我完全不知道该怎么做。我研究了 itertools.product,但这似乎只是得到组合而不是总数。我也想过索引来获取项目的价格,但又不知道如何将它与组合列表以及字典结合起来,但我也不确定如何将它与获取所有组合的列表结合起来。我有什么想法可以着手做这件事吗?

我想你可以这样做:

import pandas as pd #To display the results
from itertools import combinations, product

# Create bread dictionary 
bread = ['italian', 'wheat', 'honey oat']
bprice = [1, 2, 3]
breaddict = dict(zip(bread, bprice))

# Create meat dictionary
meat = ['roastbeef', 'ham', 'turkey', 'steak']
mprice = [3, 1, 2, 4]
meatdict= dict(zip(meat,mprice))

# Create veggie dictionary
vegetable = ['lettuce', 'onions', 'tomatoes', 'pickles']
vprice = [1, 4, 2, 3]
vegdict=dict(zip(vegetable, vprice))

# The real work is done here
# Create combinations of two veggies
# Then use that combination with bread and meat to calculate a product of sandwiches
sandwiches = product(bread,meat,combinations(vegetable,2))

# Create empty dataframe for storage and display
df=pd.DataFrame()

# Iterate through sandwiches 
# and use unpacking tuple and map with dictionary to populate dataframe
for b, m, v in sandwiches:
    df=df.append(pd.concat([pd.Series(', '.join([b, m, *v])).rename('Combinations'),
                            pd.Series(sum([breaddict[b], 
                                           meatdict[m], 
                                           *map(vegdict.get, v)])).rename('Total')], 
                           axis=1))
print(df)

输出:

                             Combinations  Total
0     italian, roastbeef, lettuce, onions      9
1   italian, roastbeef, lettuce, tomatoes      7
2    italian, roastbeef, lettuce, pickles      8
3    italian, roastbeef, onions, tomatoes     10
4     italian, roastbeef, onions, pickles     11
..                                    ...    ...
67    honey oat, steak, lettuce, tomatoes     10
68     honey oat, steak, lettuce, pickles     11
69     honey oat, steak, onions, tomatoes     13
70      honey oat, steak, onions, pickles     14
71    honey oat, steak, tomatoes, pickles     12

[72 rows x 2 columns]

没有pandas,但仍然使用itertools.combinations和itertools.product

from itertools import combinations, product

bread = ['italian', 'wheat', 'honey oat']
bprice = [1, 2, 3]
breaddict = dict(zip(bread, bprice))

# Create meat dictionary
meat = ['roastbeef', 'ham', 'turkey', 'steak']
mprice = [3, 1, 2, 4]
meatdict= dict(zip(meat,mprice))

# Create veggie dictionary
vegetable = ['lettuce', 'onions', 'tomatoes', 'pickles']
vprice = [1, 4, 2, 3]
vegdict=dict(zip(vegetable, vprice))

# The real work is done here
# Create combinations of two veggies
# Then use that combination with bread and meat to calculate a product of sandwiches
sandwiches = product(bread,meat,combinations(vegetable,2))

sandwiches_with_price = [[b,m,*v], 
                          sum([breaddict[b], meatdict[m], *map(vegdict.get, v)])) for b, m, v in sandwiches]
sandwiches_with_price

输出:

[(['italian', 'roastbeef', 'lettuce', 'onions'], 9),
 (['italian', 'roastbeef', 'lettuce', 'tomatoes'], 7),
 (['italian', 'roastbeef', 'lettuce', 'pickles'], 8),
 (['italian', 'roastbeef', 'onions', 'tomatoes'], 10),
 (['italian', 'roastbeef', 'onions', 'pickles'], 11),
 (['italian', 'roastbeef', 'tomatoes', 'pickles'], 9),
 (['italian', 'ham', 'lettuce', 'onions'], 7),
 (['italian', 'ham', 'lettuce', 'tomatoes'], 5),
 (['italian', 'ham', 'lettuce', 'pickles'], 6),
 (['italian', 'ham', 'onions', 'tomatoes'], 8),
 (['italian', 'ham', 'onions', 'pickles'], 9),
 (['italian', 'ham', 'tomatoes', 'pickles'], 7),
 (['italian', 'turkey', 'lettuce', 'onions'], 8),
 (['italian', 'turkey', 'lettuce', 'tomatoes'], 6),
 (['italian', 'turkey', 'lettuce', 'pickles'], 7),
 (['italian', 'turkey', 'onions', 'tomatoes'], 9),
 (['italian', 'turkey', 'onions', 'pickles'], 10),
 (['italian', 'turkey', 'tomatoes', 'pickles'], 8),
 (['italian', 'steak', 'lettuce', 'onions'], 10),
 (['italian', 'steak', 'lettuce', 'tomatoes'], 8),
 (['italian', 'steak', 'lettuce', 'pickles'], 9),
 (['italian', 'steak', 'onions', 'tomatoes'], 11),
 (['italian', 'steak', 'onions', 'pickles'], 12),
 (['italian', 'steak', 'tomatoes', 'pickles'], 10),
 (['wheat', 'roastbeef', 'lettuce', 'onions'], 10),
 (['wheat', 'roastbeef', 'lettuce', 'tomatoes'], 8),
 (['wheat', 'roastbeef', 'lettuce', 'pickles'], 9),
 (['wheat', 'roastbeef', 'onions', 'tomatoes'], 11),
 (['wheat', 'roastbeef', 'onions', 'pickles'], 12),
 (['wheat', 'roastbeef', 'tomatoes', 'pickles'], 10),
 (['wheat', 'ham', 'lettuce', 'onions'], 8),
 (['wheat', 'ham', 'lettuce', 'tomatoes'], 6),
 (['wheat', 'ham', 'lettuce', 'pickles'], 7),
 (['wheat', 'ham', 'onions', 'tomatoes'], 9),
 (['wheat', 'ham', 'onions', 'pickles'], 10),
 (['wheat', 'ham', 'tomatoes', 'pickles'], 8),
 (['wheat', 'turkey', 'lettuce', 'onions'], 9),
 (['wheat', 'turkey', 'lettuce', 'tomatoes'], 7),
 (['wheat', 'turkey', 'lettuce', 'pickles'], 8),
 (['wheat', 'turkey', 'onions', 'tomatoes'], 10),
 (['wheat', 'turkey', 'onions', 'pickles'], 11),
 (['wheat', 'turkey', 'tomatoes', 'pickles'], 9),
 (['wheat', 'steak', 'lettuce', 'onions'], 11),
 (['wheat', 'steak', 'lettuce', 'tomatoes'], 9),
 (['wheat', 'steak', 'lettuce', 'pickles'], 10),
 (['wheat', 'steak', 'onions', 'tomatoes'], 12),
 (['wheat', 'steak', 'onions', 'pickles'], 13),
 (['wheat', 'steak', 'tomatoes', 'pickles'], 11),
 (['honey oat', 'roastbeef', 'lettuce', 'onions'], 11),
 (['honey oat', 'roastbeef', 'lettuce', 'tomatoes'], 9),
 (['honey oat', 'roastbeef', 'lettuce', 'pickles'], 10),
 (['honey oat', 'roastbeef', 'onions', 'tomatoes'], 12),
 (['honey oat', 'roastbeef', 'onions', 'pickles'], 13),
 (['honey oat', 'roastbeef', 'tomatoes', 'pickles'], 11),
 (['honey oat', 'ham', 'lettuce', 'onions'], 9),
 (['honey oat', 'ham', 'lettuce', 'tomatoes'], 7),
 (['honey oat', 'ham', 'lettuce', 'pickles'], 8),
 (['honey oat', 'ham', 'onions', 'tomatoes'], 10),
 (['honey oat', 'ham', 'onions', 'pickles'], 11),
 (['honey oat', 'ham', 'tomatoes', 'pickles'], 9),
 (['honey oat', 'turkey', 'lettuce', 'onions'], 10),
 (['honey oat', 'turkey', 'lettuce', 'tomatoes'], 8),
 (['honey oat', 'turkey', 'lettuce', 'pickles'], 9),
 (['honey oat', 'turkey', 'onions', 'tomatoes'], 11),
 (['honey oat', 'turkey', 'onions', 'pickles'], 12),
 (['honey oat', 'turkey', 'tomatoes', 'pickles'], 10),
 (['honey oat', 'steak', 'lettuce', 'onions'], 12),
 (['honey oat', 'steak', 'lettuce', 'tomatoes'], 10),
 (['honey oat', 'steak', 'lettuce', 'pickles'], 11),
 (['honey oat', 'steak', 'onions', 'tomatoes'], 13),
 (['honey oat', 'steak', 'onions', 'pickles'], 14),
 (['honey oat', 'steak', 'tomatoes', 'pickles'], 12)]

我假设每个三明治有 2 种蔬菜、1 种肉和 1 种面包。

bread = ['italian', 'wheat', 'honey oat']
bprice = [1, 2, 3]
meat = ['roastbeef', 'ham', 'turkey', 'steak']
mprice = [3, 1, 2, 4]
vegetable = ['lettuce', 'onions', 'tomatoes', 'pickles']
vprice = [1, 4, 2, 3]

# prices are easier to manage in a dict, let's do that.
prices = {x:y for x,y in zip(bread, bprice)}
prices.update({x:y for x,y in zip(meat, mprice)})
prices.update({x:y for x,y in zip(vegetable, vprice)})


#now let's make all the vegetable combinations:
combveg = [ sorted((x ,y)) for x in vegetable for y in vegetable if len(set([x,y])) == 2 ]

# remove duplicates
combveg = list(set([tuple(x) for x in combveg]))

# now calculate all the sandwich possibilities
sandwiches = [[b, m] + list(vgs) for b in bread for m in meat for vgs in combveg]

# just have to build their prices now
sandwiches_with_price = [(sandwich, sum([prices[item] for item in sandwich])) for sandwich in sandwiches]

大多数列表操作都可以链接起来,或者使用一些生成器表达式进行优化,但目标是解释每个步骤。

另一个纯粹的Python解决方案。

from operator import itemgetter
from itertools import product, combinations

bread = ['italian', 'wheat', 'honey oat']
bprice = [1, 2, 3]
meat = ['roastbeef', 'ham', 'turkey', 'steak']
mprice = [3, 1, 2, 4]
vegetable = ['lettuce', 'onions', 'tomatoes', 'pickles']
vprice = [1, 4, 2, 3]

d = dict()
d.update(zip(bread, bprice))
d.update(zip(meat, mprice))
d.update(zip(vegetable, vprice))

for p in product(bread, meat, combinations(vegetable, 2)):
    # make 1 tuple from list and tuple (from combinations)
    p = p[0:2] + p[2]
    print('{:<40} = {}'.format(', '.join(p), sum(itemgetter(*p)(d))))

它使用了项目的产品(被使用)

此外,它还有一个字典slice:

itemgetter(*p)(d))

这从字典 d)

下面一行代码:

p = p[0:2] + p[2]

这很老套,但我不知道另一种方法可以将 combinations(vegetable, 2) 生成的元组转化为单个项目,而不是它生成的元组。

打印:

italian, roastbeef, lettuce, onions      = 9
italian, roastbeef, lettuce, tomatoes    = 7
italian, roastbeef, lettuce, pickles     = 8
italian, roastbeef, onions, tomatoes     = 10
italian, roastbeef, onions, pickles      = 11
italian, roastbeef, tomatoes, pickles    = 9
italian, ham, lettuce, onions            = 7
. . .
honey oat, steak, lettuce, tomatoes      = 10
honey oat, steak, lettuce, pickles       = 11
honey oat, steak, onions, tomatoes       = 13
honey oat, steak, onions, pickles        = 14
honey oat, steak, tomatoes, pickles      = 12