0

我想为给定列表的可能产品找到一种方法。基本上,索引后面可以跟着一个数字,例如 A1A2、A2C3... 或圆形数字 A3D1、D3B1... 下面,我有一个例子

一个例子:

the_list=['A1','A2','A3','B1','B2','B3','C1','C2','C3','D1','D2','D3']
The results should be: 
['A1A2','A1B2','A1C2','A1D2','A2A3','A2B3','A2C3','A2D3','A3A1','A3B1','A3C1','A3D1'
 'B1A2,'B2A3'...
 'C1A2'...']

到目前为止,我试过这个:

the_list=['A1','A2','A3','B1','B2','B3','C1','C2','C3','D1','D2','D3']
result=[]
for i in range(len(the_list)):
    for k in range((i%3+1),len(the_list)+1,3):
        s=str(the_list[i])+str(the_list[k%len(the_list)])
        result.append(s)

输出:

['A1A2', 'A1B2', 'A1C2', 'A1D2', 'A2A3', 'A2B3', 'A2C3', 'A2D3', 'A3B1', 'A3C1', 
    'A3D1', 'A3A1', 'B1A2', 'B1B2', 'B1C2', 'B1D2', 'B2A3', 'B2B3', 'B2C3', 'B2D3', 'B3B1', 
    'B3C1', 'B3D1', 'B3A1', 'C1A2', 'C1B2', 'C1C2', 'C1D2', 'C2A3', 'C2B3', 'C2C3', 'C2D3', 
    'C3B1', 'C3C1', 'C3D1', 'C3A1', 'D1A2', 'D1B2', 'D1C2', 'D1D2', 'D2A3', 'D2B3', 'D2C3', 
    'D2D3', 'D3B1', 'D3C1', 'D3D1', 'D3A1']

这工作正常。但是,我想让它更具可扩展性,到目前为止它会生成两个序列,如 A1A2、A1D2 ......我如何更改我的代码以使其具有可扩展性?因此,如果比例为 3,它应该以相同的方式生成 A1A2A3,...。

更新:我认为应该再有一个 for 循环来处理大小并根据该数字累积序列,但到目前为止我无法弄清楚如何去做。

4

5 回答 5

1

我想这就是你所追求的。

import itertools

def products(letters='ABCD', N=3, scale=2):
    for lets in itertools.product(letters, repeat=scale):
        for j in xrange(N):
            yield ''.join('%s%d' % (c, (i + j) % N + 1)
                          for i, c in enumerate(lets))

print list(products(scale=3))
于 2013-01-05T21:40:45.377 回答
1
  • 用于numbers = IT.cycle(numbers)生成有效数字的序列。通过使它成为一个循环,您不必对待1跟随与跟随3有任何不同。21
  • 每个项目中的字母可以由itertools.product生成。该 repeat参数在这里特别有用。正如您所说,它将允许您将生成器“缩放”到更长的序列,而无需额外的努力。
  • 您可以使用将由(以下称为)zip生成的字母 与from 组合。itertools.productletsnumbersitertools.cycle
  • ''.join(IT.chain.from_iterable只是将返回的元组列表加入zip字符串的一种方法。

import itertools as IT

def neighbor_product(letters, numbers, repeat = 2):
    N = len(numbers)
    numbers = collections.deque(numbers)
    for lets in IT.product(letters, repeat = repeat):
        for i in range(N):
            yield ''.join(IT.chain.from_iterable(zip(lets, IT.cycle(numbers))))
            numbers.rotate(-1)

letters = 'ABCD'
numbers = '123'
for item in neighbor_product(letters, numbers, repeat = 3):
    print(item)

产量

A1A2A3
A2A3A1
A3A1A2
A1A2B3
...
D3D1C2
D1D2D3
D2D3D1
D3D1D2
于 2013-01-05T23:08:34.953 回答
0

结果=[i+j for i in the_list for j in the_list]

于 2013-01-05T21:36:45.897 回答
0

我认为您正在寻找的是所有可能排列的子集。itertools.permutations()对于给定序列和给定长度 n,将所有排列的生成器返回为 n 大小的元组。我会遍历所有排列并根据您的标准过滤它们。那这个呢:

In [1]: from itertools import permutations

In [2]: the_list = ['A1','A2','A3','B1','B2','B3','C1','C2','C3','D1','D2','D3']

In [3]: results = []

In [4]: digits = list(set([elem[1] for elem in the_list]))

In [5]: digits
Out[5]: ['1', '2', '3']

In [6]: for perm in permutations(the_list, 2):
  ....:     if (int(perm[0][1])+1 == int(perm[1][1]) or 
  ....:        (perm[0][1] == digits[-1] and perm[1][1] == digits[0])): 
  ....:         results.append(''.join(perm))

In [7]: sorted(results)
Out[7]: ['A1A2', 'A1B2', 'A1C2', 'A1D2', 'A2A3', 'A2B3', 'A2C3', 
         'A2D3', 'A3A1', 'A3B1', 'A3C1', 'A3D1', 'B1A2', 'B1B2', 
         'B1C2', 'B1D2', 'B2A3', 'B2B3', 'B2C3', 'B2D3', 'B3A1', 
         'B3B1', 'B3C1', 'B3D1', 'C1A2', 'C1B2', 'C1C2', 'C1D2', 
         'C2A3', 'C2B3', 'C2C3', 'C2D3', 'C3A1', 'C3B1', 'C3C1', 
         'C3D1', 'D1A2', 'D1B2', 'D1C2', 'D1D2', 'D2A3', 'D2B3', 
         'D2C3', 'D2D3', 'D3A1', 'D3B1', 'D3C1', 'D3D1']
于 2013-01-05T21:38:50.640 回答
0

由于根据您的规范,并非每个组合都是有效的,因此检查每个可能的组合并丢弃无效的组合可能不是最好的方法。

由于每个项目的数量对于确定组合是否有效很重要,让我们首先为其创建一个查找表:

from collections import defaultdict

lookup = defaultdict(list)
for item in the_list:
    lookup[int(item[1])].append(item)

这使得获取具有特定数字的所有项目变得容易(当我们想要获取连续数字的项目时这将很有用):

lookup[1] == ['A1', 'B1', 'C1', 'D1']

现在可以按以下方式创建所有有效组合:

from itertools import product

def valid_combinations(lookup):
    min_number = min(lookup)
    max_number = max(lookup)
    for number in lookup:
        # Let's just assume here that we've only got consecutive numbers, no gaps:
        next_number = min_number if number == max_number else number + 1
        for combination in product(lookup[number], lookup[next_number]):
            yield ''.join(combination)

为了允许链接任意数量的项目,我们需要稍微修改一下:

def valid_combinations(lookup, scale = 2):
    min_number = min(lookup)
    max_number = max(lookup)
    def wrap_number(n):
        while n > max_number:
            n -= max_number + 1 - min_number
        return n
    for number in lookup:
        numbers = list(wrap_number(n) for n in range(number, number + scale))
        items = [lookup[n] for n in numbers]
        for combination in product(*items):
            yield ''.join(combination)

对于 5 级,这将产生以下结果(仅显示总共 3072 个中的前几个):

['A1A2A3A1A2', 'A1A2A3A1B2', 'A1A2A3A1C2', 'A1A2A3A1D2', 'A1A2A3B1A2', ...]
于 2013-01-05T22:49:14.863 回答