在 python 中生成特定的排列模式
Generating specific permutation patterns in python
我正在尝试为概率系统建模。我正在使用的系统涉及三个元素——称它们为 'X'、'Y' 和 'Z'。这些元素以特定类型的交替模式形成字符串,其中 X 必须与 Y 或 Z 交替(即禁止 XX、YY、ZZ、YZ 和 ZY 连接)。我想为不同的字符串长度排列所有可能序列的列表。
我最初的尝试是生成这三个字符的所有可能排列,并过滤掉任何被禁止的模式。不幸的是,对于长序列长度,排列的比例非常差。我通过生成每个序列,一次一个字符,并检查我在构建序列时提出的条件来解决这个问题。这可以防止在很早的时候生成非生产性序列,并大大减少生成的排列数量。问题是我不是一个编码员,为了实现这个目标,我不得不硬编码一堆嵌套的 for 循环。下面的代码针对长度为 5 的字符串显示。
Length = 5
Units = ['X','Y','Z']
Sequences = []
#aij is the j'th character in the sequence
for i1 in range(len(Units)):
ai1 = n[i1]
for i2 in range(len(Units)):
ai2 = Units[i2]
#If the two most recent sequential units are identical OR (Y and Z) OR (Z and Y), pass
if ai2 == ai1 or ai2==Units[1] and ai1==Units[2] or ai2==Units[2] and ai1==Units[1]:
pass
else:
#repeat for the other characters in the sequence until the final character is reached
for i3 in range(len(Units)):
ai3 = Units[i3]
if ai3 == ai2 or ai3==Units[1] and ai2==Units[2] or ai3==Units[2] and ai2==Units[1]:
pass
else:
for i4 in range(len(Units)):
ai4 = Units[i4]
if ai4 == ai3 or ai4==Units[1] and ai3==Units[2] or ai4==Units[2] and ai3==Units[1]:
pass
else:
for i5 in range(len(Units)):
ai5 = Units[i5]
if ai5 == ai4 or ai5==Units[1] and ai4==Units[2] or ai5==Units[2] and ai4==Units[1]:
pass
else:
#Append the valid sequence to my list of Sequences
a = ai1 + ai2 + ai3 + ai4 + ai5
Sequences.append(a)
print(Sequences)
输出:
['XYXYX', 'XYXZX', 'XZXYX', 'XZXZX', 'YXYXY', 'YXYXZ', 'YXZXY', 'YXZXZ', 'ZXYXY', 'ZXYXZ', 'ZXZXY', 'ZXZXZ']
我的问题是,我如何将这种类型的算法概括为一个函数,该函数只接受输入 "Length"(即字符串中的字符数)并生成我的所有序列列表中的模式?
您可以使用带递归的生成器:
def combinations(d, _len, current = []):
if len(current) == _len:
yield current
else:
for i in d:
if not current or ('X' in current and current[-1] != i):
yield from combinations(d, _len, current+[i])
results = list(map(''.join, combinations(['X','Y','Z'], 5)))
final_results = [a for i, a in enumerate(results) if a not in results[:i]]
输出:
['XYXYX', 'XYXYZ', 'XYXZX', 'XYXZY', 'XYZXY', 'XYZXZ', 'XYZYX', 'XYZYZ', 'XZXYX', 'XZXYZ', 'XZXZX', 'XZXZY', 'XZYXY', 'XZYXZ', 'XZYZX', 'XZYZY']
对于['X','Y','Z']
,可以创建9对。但是 XX, YY, ZZ, YZ, ZY
对是被禁止的。所以它仍然是XY,XZ,YX,ZX
。将其分成两个单元(units1
和units2
)以避免XX
排列。如果 length
是偶数,它只需使用 itertools 乘积对每个单元进行排列(参见:generating permutations with repetitions in python). It will produce list of tuple that can be join to string (see: Why can't I join this tuple in Python?)。附加那两个列表。
对于奇数情况,单位 1 的组合将产生任何带有 X
前缀的组合,因此将 'X' 附加到每个字符串的最后,并将 Y,Z
附加到开头。对于单元 2 组合,请执行相反的操作。它会产生不唯一的列表,所以投射到 set
只是为了让它成为唯一的
import itertools
def combine(length):
units1 = ['XY','XZ']
units2 = ['YX','ZX']
combine1 = ["".join(map(str,p)) for p in itertools.product(units1,repeat=int(length/2))]
combine2 = ["".join(map(str,p)) for p in itertools.product(units2,repeat=int(length/2))]
if (length%2 == 1):
combine1_odd = [item + 'X' for item in combine1] + ['Y' + item for item in combine1] + ['Z' + item for item in combine1]
combine2_odd = ['X' + item for item in combine2] + [item + 'Y' for item in combine2] + [item + 'Z' for item in combine2]
return list(set(combine1_odd + combine2_odd))
return list(set(combine1 + combine2))
print(combine(5))
我正在尝试为概率系统建模。我正在使用的系统涉及三个元素——称它们为 'X'、'Y' 和 'Z'。这些元素以特定类型的交替模式形成字符串,其中 X 必须与 Y 或 Z 交替(即禁止 XX、YY、ZZ、YZ 和 ZY 连接)。我想为不同的字符串长度排列所有可能序列的列表。
我最初的尝试是生成这三个字符的所有可能排列,并过滤掉任何被禁止的模式。不幸的是,对于长序列长度,排列的比例非常差。我通过生成每个序列,一次一个字符,并检查我在构建序列时提出的条件来解决这个问题。这可以防止在很早的时候生成非生产性序列,并大大减少生成的排列数量。问题是我不是一个编码员,为了实现这个目标,我不得不硬编码一堆嵌套的 for 循环。下面的代码针对长度为 5 的字符串显示。
Length = 5
Units = ['X','Y','Z']
Sequences = []
#aij is the j'th character in the sequence
for i1 in range(len(Units)):
ai1 = n[i1]
for i2 in range(len(Units)):
ai2 = Units[i2]
#If the two most recent sequential units are identical OR (Y and Z) OR (Z and Y), pass
if ai2 == ai1 or ai2==Units[1] and ai1==Units[2] or ai2==Units[2] and ai1==Units[1]:
pass
else:
#repeat for the other characters in the sequence until the final character is reached
for i3 in range(len(Units)):
ai3 = Units[i3]
if ai3 == ai2 or ai3==Units[1] and ai2==Units[2] or ai3==Units[2] and ai2==Units[1]:
pass
else:
for i4 in range(len(Units)):
ai4 = Units[i4]
if ai4 == ai3 or ai4==Units[1] and ai3==Units[2] or ai4==Units[2] and ai3==Units[1]:
pass
else:
for i5 in range(len(Units)):
ai5 = Units[i5]
if ai5 == ai4 or ai5==Units[1] and ai4==Units[2] or ai5==Units[2] and ai4==Units[1]:
pass
else:
#Append the valid sequence to my list of Sequences
a = ai1 + ai2 + ai3 + ai4 + ai5
Sequences.append(a)
print(Sequences)
输出:
['XYXYX', 'XYXZX', 'XZXYX', 'XZXZX', 'YXYXY', 'YXYXZ', 'YXZXY', 'YXZXZ', 'ZXYXY', 'ZXYXZ', 'ZXZXY', 'ZXZXZ']
我的问题是,我如何将这种类型的算法概括为一个函数,该函数只接受输入 "Length"(即字符串中的字符数)并生成我的所有序列列表中的模式?
您可以使用带递归的生成器:
def combinations(d, _len, current = []):
if len(current) == _len:
yield current
else:
for i in d:
if not current or ('X' in current and current[-1] != i):
yield from combinations(d, _len, current+[i])
results = list(map(''.join, combinations(['X','Y','Z'], 5)))
final_results = [a for i, a in enumerate(results) if a not in results[:i]]
输出:
['XYXYX', 'XYXYZ', 'XYXZX', 'XYXZY', 'XYZXY', 'XYZXZ', 'XYZYX', 'XYZYZ', 'XZXYX', 'XZXYZ', 'XZXZX', 'XZXZY', 'XZYXY', 'XZYXZ', 'XZYZX', 'XZYZY']
对于['X','Y','Z']
,可以创建9对。但是 XX, YY, ZZ, YZ, ZY
对是被禁止的。所以它仍然是XY,XZ,YX,ZX
。将其分成两个单元(units1
和units2
)以避免XX
排列。如果 length
是偶数,它只需使用 itertools 乘积对每个单元进行排列(参见:generating permutations with repetitions in python). It will produce list of tuple that can be join to string (see: Why can't I join this tuple in Python?)。附加那两个列表。
对于奇数情况,单位 1 的组合将产生任何带有 X
前缀的组合,因此将 'X' 附加到每个字符串的最后,并将 Y,Z
附加到开头。对于单元 2 组合,请执行相反的操作。它会产生不唯一的列表,所以投射到 set
只是为了让它成为唯一的
import itertools
def combine(length):
units1 = ['XY','XZ']
units2 = ['YX','ZX']
combine1 = ["".join(map(str,p)) for p in itertools.product(units1,repeat=int(length/2))]
combine2 = ["".join(map(str,p)) for p in itertools.product(units2,repeat=int(length/2))]
if (length%2 == 1):
combine1_odd = [item + 'X' for item in combine1] + ['Y' + item for item in combine1] + ['Z' + item for item in combine1]
combine2_odd = ['X' + item for item in combine2] + [item + 'Y' for item in combine2] + [item + 'Z' for item in combine2]
return list(set(combine1_odd + combine2_odd))
return list(set(combine1 + combine2))
print(combine(5))