我正在寻找一些关于如何更好地处理几个功能的建议。
我有一组5个对象,每个对象有6个属性,对象的数量和属性的数量都可以改变。
我需要在每个可能的对象组合上迭代每个可能的属性组合。集合中的任何对象都不能在集合中具有相同的值。并且对于每个对象属性,有n个可能的值(其中n是设置大小)。适用于属性的值不适用于其他属性。即。 attributeA的值永远不会是attributeB的值。
目前,我将对象表示为列表列表。 例如。 [[obj1attr_A,obj1attrB],[obj2attr_A,obj2attr_B]]等等
问题是itertools.combinations返回了太多无效的redundent组合(即,更经常出现一次的值)。如果我使用生成器只返回有效的组合,那么它很慢,从而无法有效地产生正确的组合。有没有办法有效地过滤itertools.combinations中的结果?
#keywords is a list of possible values for each attribute
Solver.get_unique_combinations(
itertools.combinations(itertools.product(*keywords), 5))
def get_unique_combinations(combinations):
for combination in combinations:
flat = [item for sublist in combination for item in sublist]
if len(set(flat)) < len(flat):
continue
yield combination
我也尝试过使用ifilter同样的问题(下面),实际上我唯一可以看到我能够做到这一点的方法就是使用itertools.combinations以外的东西来返回具有唯一值的对象集在每个,并以某种方式完全跳过了对过滤器的需求。
return itertools.ifilter(lambda x: Solver.get_unique_combinations(x),
itertools.combinations(itertools.product(*keywords), 5))
@staticmethod
def get_unique_combinations(x):
if len(
set(str(x).replace('[', '')
.replace('[', '')
.replace(',', '')
.replace('(', '')
.replace(')', '')
.split())) == len(x) * len(x[0]):
return True
return False
**编辑:根据要求 - 简短的可编辑版本:
import itertools
def has_unique_values(iterable, attr_count):
seen = set()
seen_add = seen.add
counter = 0
for element in itertools.ifilterfalse(seen.__contains__,
itertools.chain(iterable)):
seen_add(element)
counter += 1
return counter == attr_count
keywords = [
["australia", "sweden", "germany", "france", "italy"],
["lion", "tiger", "otter", "bird", "fish"],
["table", "chair", "cloth", "couch", "tv"],
["apple", "orange", "pear", "grape", "tomato"],
["onion", "carrot", "mushroom", "kale", "spinach"]]
keyword_combinations = itertools.product(*keywords)
population = len(keywords[0])
attr_count = len(keywords)
unique_count = population * attr_count
for c in itertools.ifilter(lambda x: has_unique_values(x, unique_count),
itertools.combinations(keyword_combinations, population)):
print c #doesnt get to here