python - 检查排列是否存在/组合是否唯一

时间:2014-02-25 04:17:17

标签: python list unique permutation

我有以下代码,可以创建属于特定价格范围的水果,蔬菜和饮料的组合:

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)

等等。这给了我更多的麻烦,所以任何帮助都会受到赞赏。

3 个答案:

答案 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]