假设我有一个列表['a', 'b', '1', '2']
。我需要以相同顺序生成此列表的所有可能组合,但要在字符之间添加破折号。
所以我需要给出以下所有答案:
a-b12
ab-12
ab1-2
a-b-12
a-b1-2
ab-1-2
a-b-1-2
我想对更长的字符串执行此操作,该字符串将具有更多的组合。我该怎么办?
编辑:伙计们,所有这些评论都非常有帮助!我非常感谢每个人帮助我解决这个问题,而不是详细解释它!
答案 0 :(得分:5)
a b 1 2
^ ^ ^
| | |
0 1 2
想象一下,字符之间的每个空格都有一个索引。在a
和b
之间是索引0。在b
和1
之间是索引1。在1
和2
之间是索引2。 >
每个空间都可以连字符或不带破折号。
您要检查破折号或无任何组合。如果您将每个空间视为一个“位”,其中每个位可以为0(空)或1(破折号),则可以很好地映射到检查 b 位的所有组合,其中 b 比您拥有的商品少一。
要检查所有位组合,只需从1迭代到2 b 。 (跳过0以确保始终至少有一个破折号。)对于每次迭代,只要设置了相应的位,就插入一个破折号。
如果我们只是发出破折号或空格,而现在暂时忽略ab12
字符,则是这样。
仅破折号
items = ['a', 'b', '1', '2']
bits = len(items) - 1
for n in range(1, 2**bits):
print(''.join('-' if n & (1<<i) else ' ' for i in range(bits)))
输出
-
-
--
-
- -
--
---
在后两行中发生了很多事情。让我分解一下。
for n in range(1, 2**bits)
-这是我上面解释的直接翻译。它从1循环到2 b 。唯一的区别是我称它为 bits 而不是 b 。使用更多描述性的变量名可以使代码受益。
(<expr> for i in range(bits))
—括号内的for
循环称为generator expression。这是一种在一行代码中生成一系列项目的紧凑方法。为 i 的每个值评估 expr 。
'-' if n & (1<<i) else ' '
—上面的 expr 是这项工作。这是算法的核心:对于每个空间,我们发出一个'-'
或一个' '
。秘密位n & (1<<i)
是formula for testing if a bit is set。
如果您不熟悉&
,按位AND和<<
之类的按位运算,请向左移动,建议您在Google上搜索以获取更多信息。它本身就是一个非常有趣的话题,我可以花一些页面来解释。
''.join(...)
—将我们生成的所有'-'
和' '
字符串连接成一个大字符串。
最后一步是散布项目和破折号。我们可以通过在上面的代码中添加几位来做到这一点。首先,我们将在每个可能的破折号之前加items[i]
。其次,我们将items[-1]
添加到末尾。这两个步骤有效地将破折号包围在列表中。
项目和破折号
items = ['a', 'b', '1', '2']
bits = len(items) - 1
for n in range(1, 2**bits):
print(''.join(items[i] + ('-' if n & (1<<i) else '') for i in range(bits)) + items[-1])
输出
a-b12
ab-12
a-b-12
ab1-2
a-b1-2
ab-1-2
a-b-1-2
答案 1 :(得分:1)
为清晰起见,与速度相反:
def insert( seq ):
answers = []
if seq[1:]:
for subseq in insert( seq[1:] ):
answers.append( [ seq[0], ] + subseq )
answers.append( [ seq[0],'-' ] + subseq )
else:
answers.append( seq )
return answers
for answer in insert(['a','b','1','2'])[1:]:
print ''.join(answer)
输出是所需的(尽管我也想输出无破折号的解决方案):
a-b12
ab-12
a-b-12
ab1-2
a-b1-2
ab-1-2
a-b-1-2
答案 2 :(得分:0)
这是一个简单的分步解决方案。它可能比其他答案效率低下,但它是一种直接的方法。
您可以首先使用@mjwills's above comment列出n-1
的所有二进制组合:
from itertools import product
lst = ['a', 'b', '1', '2']
def binary_combinations(bits):
return list(product([0, 1], repeat=bits))
binary_combs = binary_combinations(bits=len(lst) - 1)
# [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
然后,您可以在每个项目之间插入''
列表。这使得以后加入变得更容易。
def intersperse(lst, item):
result = [item] * (len(lst) * 2 - 1)
result[0::2] = lst
return result
interspersed_items = intersperse(lst, '')
# ['a', '', 'b', '', '1', '', '2']
最后,您可以输出替换为-
和str.join()
的结果组合:
for comb in binary_combs[1:]:
result = interspersed_items[:]
for i, binary in enumerate(comb):
if binary == 1:
result[i * 2 + 1] = '-'
print("".join(result))
输出以下组合。以下顺序与问题中的顺序不同,但这不应该成为问题吗?
ab1-2
ab-12
ab-1-2
a-b12
a-b1-2
a-b-12
a-b-1-2