Python:找到所有可能的字符组合与字符序列(分词)

问题描述:

我正在做一些分词实验,如下所示。Python:找到所有可能的字符组合与字符序列(分词)

lst是一个字符序列,而output是所有可能的单词。

lst = ['a', 'b', 'c', 'd'] 

def foo(lst): 
    ... 
    return output 

output = [['a', 'b', 'c', 'd'], 
      ['ab', 'c', 'd'], 
      ['a', 'bc', 'd'], 
      ['a', 'b', 'cd'], 
      ['ab', 'cd'], 
      ['abc', 'd'], 
      ['a', 'bcd'], 
      ['abcd']] 

我在itertools库检查combinationspermutations
也试过combinatorics
但是,似乎我看着错误的一面,因为这不是纯粹的置换和组合...

看来我可以通过使用大量循环来实现这一点,但效率可能很低。所以像['ba', 'dc']['cd', 'ab']组合是无效的

编辑

词序是很重要的。

从左至右的顺序应始终为

编辑

@斯图尔特的解决方案并不在Python 2.7.6工作

编辑

@斯图尔特的解决方案确实在Python 2.7.6工作,请参见下面的评论。

+0

请参阅我的代码在Python 2.7.3中使用[here](http://ideone.com/ufVuEm)和Python 3.2.3中的[here](http://ideone.com/N4y9t7) – Stuart 2014-12-03 10:33:23

itertools.product的确应该能够帮助你。

这个想法是这样的: - 考虑A1,A2,...,由板块分隔的AN。将会有N-1块平板。 如果有板块存在分段。如果没有平板,则有一个连接。因此,对于给定的长度为N的序列,应该有2 ^(N-1)个这样的组合。

就像下面

import itertools 
lst = ['a', 'b', 'c', 'd'] 
combinatorics = itertools.product([True, False], repeat=len(lst) - 1) 

solution = [] 
for combination in combinatorics: 
    i = 0 
    one_such_combination = [lst[i]] 
    for slab in combination: 
     i += 1 
     if not slab: # there is a join 
      one_such_combination[-1] += lst[i] 
     else: 
      one_such_combination += [lst[i]] 
    solution.append(one_such_combination) 

print solution 
+0

我选择了这个答案,因为花费最少的时间,但其他的解决方案也有很大的 – amigcamel 2014-12-03 15:02:26

有8个选项,每个镜像二进制数0到7:

000 
001 
010 
011 
100 
101 
110 
111 

每个0和1代表是否该索引处的2个字母“胶合”在一起。 0表示否,1表示是。

>>> lst = ['a', 'b', 'c', 'd'] 
... output = [] 
... formatstr = "{{:0{}.0f}}".format(len(lst)-1) 
... for i in range(2**(len(lst)-1)): 
...  output.append([]) 
...  s = "{:b}".format(i) 
...  s = str(formatstr.format(float(s))) 
...  lstcopy = lst[:] 
...  for j, c in enumerate(s): 
...   if c == "1": 
...    lstcopy[j+1] = lstcopy[j] + lstcopy[j+1] 
...   else: 
...    output[-1].append(lstcopy[j]) 
...  output[-1].append(lstcopy[-1]) 
... output 
[['a', 'b', 'c', 'd'], 
['a', 'b', 'cd'], 
['a', 'bc', 'd'], 
['a', 'bcd'], 
['ab', 'c', 'd'], 
['ab', 'cd'], 
['abc', 'd'], 
['abcd']] 
>>> 
+0

您的代码isn不为lst = ['a','b','c','d','e']工作。 – 2014-12-03 04:23:36

+2

谢谢!修复它以适用于更多字母的情况。即使我没有得到接受,这是一个有趣的练习:) – twasbrillig 2014-12-03 04:34:04

+0

^哈哈!我赞成你的。我们都有相同的解决方案。你快了! :-) – Sriram 2014-12-03 04:55:52

#!/usr/bin/env python 
from itertools import combinations 
a = ['a', 'b', 'c', 'd'] 
a = "".join(a) 
cuts = [] 
for i in range(0,len(a)): 
    cuts.extend(combinations(range(1,len(a)),i)) 
for i in cuts: 
    last = 0 
    output = [] 
    for j in i: 
     output.append(a[last:j]) 
     last = j 
    output.append(a[last:]) 
    print(output) 

输出:

zsh 2419 % ./words.py 
['abcd'] 
['a', 'bcd'] 
['ab', 'cd'] 
['abc', 'd'] 
['a', 'b', 'cd'] 
['a', 'bc', 'd'] 
['ab', 'c', 'd'] 
['a', 'b', 'c', 'd'] 
+0

我不能upvote你。我在你的回答下写下评论的理由。 你的代码我小那么我的,这是很好的,但是,我的机器上的代码不到风度很好地工作:( – 2014-12-03 04:55:16

+0

这实际上是斯图尔特的回答,不是我的,但Sririam upvoted矿山所以这一切都很好。 – twasbrillig 2014-12-03 05:06:14

您可以使用递归发生器:

def split_combinations(L): 
    for split in range(1, len(L)): 
     for combination in split_combinations(L[split:]): 
      yield [L[:split]] + combination 
    yield [L] 

print (list(split_combinations('abcd'))) 

编辑。我不确定这会如何扩展长字符串,以及它达到Python递归限制的程度。与其他一些答案类似,您也可以使用combinationsitertools开始处理每个可能的组合点。

这些似乎都按预期在Python 2.7(see here)和Python 3.2(here)工作。正如@twasbrillig所说,确保你缩进如图所示。

+0

我没有看到![‘ABC’‘d’]在输出 – 2014-12-03 04:28:35

+0

我真的看到它 – twasbrillig 2014-12-03 04:37:22

+0

'在文献[1]:?DEF split_combinations(L) : ...:在范围(,LEN(L)1)拆分: ...:用于组合在split_combinations(L [分裂:]): ...:产率[L [:分割]] +组合 ...:收益率[L] ...: In [2]:print(list(split_combinatio ns('abcd'))) [['a','b','cd'],['a','bcd'],['a','bcd'],['abcd'], ['ab','cd'],['abcd'],['abcd']]' – 2014-12-03 04:41:17