Python 模型的嵌套置换
我正在编写一个程序,它采用字符串的排列“模型”,并根据该模型输出所有排列。模型的外观如下所示:Python 模型的嵌套置换,python,algorithm,permutation,combinatorics,itertools,Python,Algorithm,Permutation,Combinatorics,Itertools,我正在编写一个程序,它采用字符串的排列“模型”,并根据该模型输出所有排列。模型的外观如下所示: model = Mix([ [ "this", PickOne(["is", "isn't"]) ], PickOne([ Mix([ "absolutely", "great" ]) ]) ]) class Mix(list): def __ini
model = Mix([
[
"this",
PickOne(["is", "isn't"])
],
PickOne([
Mix([
"absolutely",
"great"
])
])
])
class Mix(list):
def __init__(self, *args, **kwargs):
super(Mix, self).__init__(*args, **kwargs)
self.permutations = []
for L in range(0, len(self)+1):
for subset in itertools.combinations(self, L):
subset_permutations = itertools.permutations(subset)
self.permutations.extend(subset_permutations)
在输出的排列中
列表
对象将按顺序输出包含的对象Mix
对象将以任何可能的最大长度(包括零)以每个可能的顺序输出包含的对象PickOne
对象一次只输出其包含的一个对象[
["this", "is"],
["this", "isn't"],
["this", "is", "absolutely"],
["this", "is", "great"],
["this", "isn't", "absolutely"],
["this", "isn't", "great"],
["absolutely"],
["great"],
["absolutely", "this", "is"],
["great", "this", "is"],
["absolutely", "this", "isn't"],
["great", "this", "isn't"],
[]
]
到目前为止,我已经为Mix
类实现了如下排列:
model = Mix([
[
"this",
PickOne(["is", "isn't"])
],
PickOne([
Mix([
"absolutely",
"great"
])
])
])
class Mix(list):
def __init__(self, *args, **kwargs):
super(Mix, self).__init__(*args, **kwargs)
self.permutations = []
for L in range(0, len(self)+1):
for subset in itertools.combinations(self, L):
subset_permutations = itertools.permutations(subset)
self.permutations.extend(subset_permutations)
我的PickOne
课程就是这样
class PickOne(list):
pass
我正计划在我的主函数中对其进行测试并进行相应的处理(如果type(obj)是PickOne:…
)
itertools
为更简单的用例提供了简化和效率,但是我不知道它将如何帮助我实现这个实现(除了我在Mix
中已经实现的之外)。关于如何使用itertools
来帮助上述的Pythonic实现,您有什么想法吗?我对所有这些组合感到困惑,但我认为您的Mix
类还必须生成所有这些排列的产品。我创建了一个类似的模型来测试这一点。这可能与您的工作方式有所不同,但应易于适应:
class CombModel:
def __init__(self, *options):
self.options = options
class Atom(CombModel):
def __iter__(self):
for x in self.options:
yield x
class All(CombModel):
def __iter__(self):
for prod in itertools.product(*self.options):
yield prod
class One(CombModel):
def __iter__(self):
for x in self.options:
for y in x:
yield y
class Mix(CombModel):
def __iter__(self):
for n in range(len(self.options) + 1):
for perm in itertools.permutations(self.options, n):
for prod in itertools.product(*perm):
yield prod
CombModel
仅为所有子类提供var-arg构造函数Atom
是模型中的一个“叶子”,因此我可以“迭代”单个字符串或整数。这将在所有其他类中保存一些if/else
逻辑All
在您的模型中似乎是简单的列表,生成不同选项的产品One
和Mix
对应于您的PickOne
和Mix
使用这个相当简单的模型comb=Mix(全部(原子(1),原子(21,22)),一个(原子(31,32),原子(4))
我得到了以下组合:
()
((1, 21),)
((1, 22),)
(31,)
(32,)
(4,)
((1, 21), 31)
((1, 21), 32)
((1, 21), 4)
((1, 22), 31)
((1, 22), 32)
((1, 22), 4)
(31, (1, 21))
(31, (1, 22))
(32, (1, 21))
(32, (1, 22))
(4, (1, 21))
(4, (1, 22))
()
(('this', 'is'),)
(('this', "isn't"),)
((),)
(('absolutely',),)
(('great',),)
(('absolutely', 'great'),)
(('great', 'absolutely'),)
(('this', 'is'), ())
(('this', 'is'), ('absolutely',))
(('this', 'is'), ('great',))
(('this', 'is'), ('absolutely', 'great'))
(('this', 'is'), ('great', 'absolutely'))
(('this', "isn't"), ())
(('this', "isn't"), ('absolutely',))
(('this', "isn't"), ('great',))
(('this', "isn't"), ('absolutely', 'great'))
(('this', "isn't"), ('great', 'absolutely'))
((), ('this', 'is'))
((), ('this', "isn't"))
(('absolutely',), ('this', 'is'))
(('absolutely',), ('this', "isn't"))
(('great',), ('this', 'is'))
(('great',), ('this', "isn't"))
(('absolutely', 'great'), ('this', 'is'))
(('absolutely', 'great'), ('this', "isn't"))
(('great', 'absolutely'), ('this', 'is'))
(('great', 'absolutely'), ('this', "isn't"))
您的模型可以解释为:
model = Mix(
All(
Atom("this"),
One(Atom("is"), Atom("isn't"))
),
One(
Mix(
Atom("absolutely"),
Atom("great")
)
)
)
并给出了这些组合:
()
((1, 21),)
((1, 22),)
(31,)
(32,)
(4,)
((1, 21), 31)
((1, 21), 32)
((1, 21), 4)
((1, 22), 31)
((1, 22), 32)
((1, 22), 4)
(31, (1, 21))
(31, (1, 22))
(32, (1, 21))
(32, (1, 22))
(4, (1, 21))
(4, (1, 22))
()
(('this', 'is'),)
(('this', "isn't"),)
((),)
(('absolutely',),)
(('great',),)
(('absolutely', 'great'),)
(('great', 'absolutely'),)
(('this', 'is'), ())
(('this', 'is'), ('absolutely',))
(('this', 'is'), ('great',))
(('this', 'is'), ('absolutely', 'great'))
(('this', 'is'), ('great', 'absolutely'))
(('this', "isn't"), ())
(('this', "isn't"), ('absolutely',))
(('this', "isn't"), ('great',))
(('this', "isn't"), ('absolutely', 'great'))
(('this', "isn't"), ('great', 'absolutely'))
((), ('this', 'is'))
((), ('this', "isn't"))
(('absolutely',), ('this', 'is'))
(('absolutely',), ('this', "isn't"))
(('great',), ('this', 'is'))
(('great',), ('this', "isn't"))
(('absolutely', 'great'), ('this', 'is'))
(('absolutely', 'great'), ('this', "isn't"))
(('great', 'absolutely'), ('this', 'is'))
(('great', 'absolutely'), ('this', "isn't"))
请注意,这些仍然是嵌套列表(实际上是元组),但之后可以很容易地进行嵌套。此外,由于Mix
的“零或多”特性,存在一些伪重复(展平时即为重复)。但除此之外,这看起来相当接近您的预期输出
仔细检查后,可能确实需要先展平,以便PickOne只从混合物中选择一种,而不是整个混合物
class All(CombModel):
def __iter__(self):
for prod in itertools.product(*self.options):
yield flat(prod) # flatten here
class One(CombModel):
def __iter__(self):
for x in self.options:
for y in flat(x): # flatten here
yield y
class Mix(CombModel):
def __iter__(self):
for n in range(len(self.options) + 1):
for perm in itertools.permutations(self.options, n):
for prod in itertools.product(*perm):
yield flat(prod) # flatten here
剔除重复项后,结果如下:
()
('absolutely',)
('absolutely', 'this', 'is')
('absolutely', 'this', "isn't")
('great',)
('great', 'this', 'is')
('great', 'this', "isn't")
('this', 'is')
('this', 'is', 'absolutely')
('this', 'is', 'great')
('this', "isn't")
('this', "isn't", 'absolutely')
('this', "isn't", 'great')
我很难理解这一点。因此,即使是一个简单的“列表”,如果它包含其他“排列模型”,也应该产生这些模型所有可能结果的乘积,对吗?没错。嗯,当一个One
包含一个All
对象时,这似乎不起作用-它不选择整个All
,而是选择其内部内容之一。这里有一个要点:@Julien这不就是它的工作原理吗?至少这与您的示例中一个(Mix(…)的工作方式是一致的。另外,我的第一个版本,并没有扁平化,应该像这样工作,一个选择所有的内容。你们说得对。我的规范并不完美,但我通过在All
中省略flatten
实现了我所需要的功能。再次感谢