我有以下代码,可以创建属于特定价格范围的水果,蔬菜和饮料的组合:
fruits = [('apple', 1), ('banana', 2), ('orange', 3)]
veggies = [('tomato', 1), ('cucumber', 2), ('onion', 3)]
drinks = [('water', 1), ('juice', 2), ('soda', 3)]
for fruit1 in fruits:
for fruit2 in fruits:
for veggie1 in veggies:
for veggie2 in veggies:
for drink1 in drinks:
for drink2 in drinks:
if 12 <= fruit1[1]+fruit2[1]+veggie1[1]+veggie2[1]+drink1[1]+drink2[1] <= 14:
if fruit1 != fruit2:
if veggie1 != veggie2:
if drink1 != drink2:
combos.append((fruit1[0], fruit2[0], veggie1[0], veggie2[0], drink1[0], drink2[0], fruit1[1]+fruit2[1]+veggie1[1]+veggie2[1]+drink1[1]+drink2[1]))
检查以确保它不会选择相同的水果/蔬菜/饮料两次,但我需要确保这些组合是唯一的。
例如,如果我最终
('apple', 'banana', 'tomato', 'cucumber', 'water', 'soda', 10)
我不想要
('banana', 'apple', 'tomato', 'cucumber', 'water', 'soda', 10)
等等。这给了我更多的麻烦,所以任何帮助都会受到赞赏。
答案 0 :(得分:2)
您可以像这样处理数据
prices = {k:v for items in [fruits, veggies, drinks] for k, v in items}
fru,veg,dri=[i[0] for i in fruits],[i[0] for i in veggies],[i[0] for i in drinks]
from itertools import combinations, product, chain
for items in product(*(combinations(i, r = 2) for i in (fru, veg, dri))):
total = sum(prices[i] for item in items for i in item)
if 12 <= total <= 14:
print tuple(chain.from_iterable(items)) + (total,)
<强>输出强>
('apple', 'banana', 'tomato', 'onion', 'juice', 'soda', 12)
('apple', 'banana', 'cucumber', 'onion', 'water', 'soda', 12)
('apple', 'banana', 'cucumber', 'onion', 'juice', 'soda', 13)
('apple', 'orange', 'tomato', 'cucumber', 'juice', 'soda', 12)
('apple', 'orange', 'tomato', 'onion', 'water', 'soda', 12)
('apple', 'orange', 'tomato', 'onion', 'juice', 'soda', 13)
('apple', 'orange', 'cucumber', 'onion', 'water', 'juice', 12)
('apple', 'orange', 'cucumber', 'onion', 'water', 'soda', 13)
('apple', 'orange', 'cucumber', 'onion', 'juice', 'soda', 14)
('banana', 'orange', 'tomato', 'cucumber', 'water', 'soda', 12)
('banana', 'orange', 'tomato', 'cucumber', 'juice', 'soda', 13)
('banana', 'orange', 'tomato', 'onion', 'water', 'juice', 12)
('banana', 'orange', 'tomato', 'onion', 'water', 'soda', 13)
('banana', 'orange', 'tomato', 'onion', 'juice', 'soda', 14)
('banana', 'orange', 'cucumber', 'onion', 'water', 'juice', 13)
('banana', 'orange', 'cucumber', 'onion', 'water', 'soda', 14)
如果您只想在drinks
中选择一个元素,那么您可以像这样更改组合部分
d = {0: 2, 1: 2, 2: 1}
for items in product(*(combinations(j, r=d.get(i)) for i, j in enumerate((fru,veg,dri)))):
通过该更改,输出变为
('apple', 'orange', 'cucumber', 'onion', 'soda', 12)
('banana', 'orange', 'tomato', 'onion', 'soda', 12)
('banana', 'orange', 'cucumber', 'onion', 'juice', 12)
('banana', 'orange', 'cucumber', 'onion', 'soda', 13)
答案 1 :(得分:1)
你可以创建一组frozensets,这将消除冗余集:
>>> tup_1 = ('apple', 'banana', 'tomato', 'cucumber', 'water', 'soda', 10)
>>> tup_2 = ('banana', 'apple', 'tomato', 'cucumber', 'water', 'soda', 10)
>>> fs_1 = frozenset(tup_1)
>>> fs_2 = frozenset(tup_2)
>>> set([fs_1, fs_2])
set([frozenset(['tomato', 'apple', 10, 'water', 'cucumber', 'soda', 'banana'])])
每个项目都需要frozenset
,因为elements of a set
must be hashable。请记住,这种方法会丢失订单。
此外,itertools.combinations将确保您不会获得多余的项目:
import itertools
fruits = [('apple', 1), ('banana', 2), ('orange', 3)]
veggies = [('tomato', 1), ('cucumber', 2), ('onion', 3)]
drinks = [('water', 1), ('juice', 2), ('soda', 3)]
combs=(itertools.combinations(fruits, 2),
itertools.combinations(veggies, 2),
itertools.combinations(drinks, 2))
multi_combs = [list(itertools.chain.from_iterable(i))
for i in itertools.product(*combs)]
print(len(multi_combs))
打印
27
然后你可以过滤:
filtered_combs = [i for i in multi_combs
if 12 <= sum(p for _, p in i) <= 14]
和
len(filtered_combs)
是
16
以漂亮的方式打印物品:
printable = [list(itertools.chain((j for j, _ in i),
[sum(p for _, p in i),]))
for i in filtered_combs]
pprint.pprint(printable)
打印
[['apple', 'banana', 'tomato', 'onion', 'juice', 'soda', 12],
['apple', 'banana', 'cucumber', 'onion', 'water', 'soda', 12],
['apple', 'banana', 'cucumber', 'onion', 'juice', 'soda', 13],
['apple', 'orange', 'tomato', 'cucumber', 'juice', 'soda', 12],
['apple', 'orange', 'tomato', 'onion', 'water', 'soda', 12],
['apple', 'orange', 'tomato', 'onion', 'juice', 'soda', 13],
['apple', 'orange', 'cucumber', 'onion', 'water', 'juice', 12],
['apple', 'orange', 'cucumber', 'onion', 'water', 'soda', 13],
['apple', 'orange', 'cucumber', 'onion', 'juice', 'soda', 14],
['banana', 'orange', 'tomato', 'cucumber', 'water', 'soda', 12],
['banana', 'orange', 'tomato', 'cucumber', 'juice', 'soda', 13],
['banana', 'orange', 'tomato', 'onion', 'water', 'juice', 12],
['banana', 'orange', 'tomato', 'onion', 'water', 'soda', 13],
['banana', 'orange', 'tomato', 'onion', 'juice', 'soda', 14],
['banana', 'orange', 'cucumber', 'onion', 'water', 'juice', 13],
['banana', 'orange', 'cucumber', 'onion', 'water', 'soda', 14]]
答案 2 :(得分:1)
这并不是一种有效的方法,因为一旦你花了超过14个单位,你就不需要继续搜索了。但是你可以使用itertools
来简化 - 或者至少是扁平化 - 蛮力方法:
from itertools import combinations, product, chain
fruits = [('apple', 1), ('banana', 2), ('orange', 3)]
veggies = [('tomato', 1), ('cucumber', 2), ('onion', 3)]
drinks = [('water', 1), ('juice', 2), ('soda', 3)]
options = fruits, veggies, drinks
possibles = product(*(combinations(opt, 2) for opt in options))
purchases = (list(chain.from_iterable(p)) for p in possibles)
within_range = [p for p in purchases if 12 <= sum(price for _, price in p) <= 14]
产生
>>> within_range[0]
[('apple', 1), ('banana', 2), ('tomato', 1), ('onion', 3), ('juice', 2), ('soda', 3)]
>>> within_range[-1]
[('banana', 2), ('orange', 3), ('cucumber', 2), ('onion', 3), ('water', 1), ('soda', 3)]
>>> [sum(p for _,p in w) for w in within_range]
[12, 12, 13, 12, 12, 13, 12, 13, 14, 12, 13, 12, 13, 14, 13, 14]