2013-01-05 25 views
0

我想找到給定列表的可能產品的一種方法。 基本上索引可以跟隨一個數字,旁邊數如A1A2,A2C3 ...或圓形的數目A3D1,D3B1 ...下面,我有一個例子Python使給定列表產品的可擴展性更大

一個例子:

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循環,是以大小的關懷和積累基於這個數字序列,但我無法弄清楚迄今爲止如何。

+0

如果我正確讀取結果 - 任何 「連接」(如果視爲網格) - 或者水平/垂直/對角線是候選? –

+0

沒關係 - 我認爲我已經分析了一下 - 看看@Amber建議的'itertools' –

回答

1
  • 使用numbers = IT.cycle(numbers)生成有效 數字序列。By making it a cycle,您不必按1處理以下3任何不同於2以下1
  • 每個項目中的字母可以由itertools.product生成。這裏參數 repeat特別有用。如您所說,它將允許您將 「縮放」到較長的序列,而不需要額外的努力。
  • 您可以使用zipnumbersitertools.product(下文稱爲lets)產生的來信 itertools.cycle結合起來。
  • ''.join(IT.chain.from_iterablejust a way to join the list of 由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 
+0

雖然這不會產生像「?2?3?1」這樣的東西,並且如果我理解它的概括,那麼它應該。 – DSM

+0

@DSM:謝謝;確實在我的代碼中有錯誤。我忘記提前編號,以便枚舉每個可能的數字序列。我希望這是你所指的錯誤:) – unutbu

+0

是的,就是這樣! – DSM

0

結果= [我在the_list + J爲我在the_list對J]

+0

這產生了諸如「A1A1」,「A2A2」,「C2C2」等的組合,這不是OP想要的。 – pemistahl

+0

然後得到這個結果:** result = [i + j爲i在the_list中爲i,如果i!= j] ** – Kowalski

+0

這給出所有排列,但不根據OP想要的標準對它們進行過濾。另外,'itertools.permutations(the_list,2)'比你的列表理解更有效率。不要重新發明輪子。使用Python的標準庫。 – pemistahl

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'] 
+0

A1A3對我的情況無效! –

+0

@JohnSmith我編輯了我的解決方案。請再看一遍。這是你想要的嗎? – pemistahl

+0

是的,但它應該更具可擴展性,你只限制兩個序列。例如,像A1A2A3A4A5那樣的更大尺寸...... –

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)) 
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'] 

創建的所有有效組合,現在可以做如下:

,當我們想要得到consequtive號項目)將是有益的

爲了可以鏈接任何數量的項目,我們需要修改一下:

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', ...]