引入
本文組合邏輯的講解,與代碼,都是基於python的。
我們在實際編程中,會遇到多個元素做組合的過程,比如,給定如下4個列表
list1 = ['A', 'B']
list2 = ['C', 'D']
list3 = ['E','F','G']
list4 = ['H', 'I']
列表中的元素(A/B/C等),這裏用的是string。實際情況中,也可以是int,或其他類型的instance(比如list)。
若要求每個list中的元素,分別於其他list的元素做組合,最終組合結果如下,該怎麼求解呢?
[['A', 'C', 'E', 'H'],
['A', 'C', 'E', 'I'],
['A', 'C', 'F', 'H'],
['A', 'C', 'F', 'I'],
['A', 'C', 'G', 'H'],
['A', 'C', 'G', 'I'],
['A', 'D', 'E', 'H'],
['A', 'D', 'E', 'I'],
['A', 'D', 'F', 'H'],
['A', 'D', 'F', 'I'],
['A', 'D', 'G', 'H'],
['A', 'D', 'G', 'I'],
['B', 'C', 'E', 'H'],
['B', 'C', 'E', 'I'],
['B', 'C', 'F', 'H'],
['B', 'C', 'F', 'I'],
['B', 'C', 'G', 'H'],
['B', 'C', 'G', 'I'],
['B', 'D', 'E', 'H'],
['B', 'D', 'E', 'I'],
['B', 'D', 'F', 'H'],
['B', 'D', 'F', 'I'],
['B', 'D', 'G', 'H'],
['B', 'D', 'G', 'I']]
這裏最簡單的解法,就是用4個for循環來實現。但實際情況中,list的個數是可變的,那就無法用固定個數的for訓練來實現了。
我們下面就講解這個問題的求解邏輯,與代碼實現。
組合的邏輯過程
首先,把所有list都裝在一個list中,比如
all_list = [list1, list2, list3, list4]
然後,設置一個空的result的list,用來存儲最終結果
result = [[]]
這裏是list of list,其中的內層list設置爲空list很重要,這保證了下面邏輯的正確進行。
接下來,遍歷各個子list的元素,並與result中的元素做組合:
for pool in all_list:
tmp = []
for x in result:
for y in pool:
tmp.append(x+[y])
result = tmp
爲了看懂上面代碼的組合邏輯過程,我們寫一個簡化的實例,如下:
all_list = [['A','B'],['C','D','E']]
result = [[]]
for pool in all_list:
tmp = []
for x in result:
for y in pool:
tmp.append(x+[y])
print(tmp)
result = tmp
跑起來,得到的輸出如下
[['A'], ['B']]
[['A', 'C'], ['A', 'D'], ['A', 'E']]
[['A', 'C'], ['A', 'D'], ['A', 'E'], ['B', 'C'], ['B', 'D'], ['B', 'E']]
通過輸出,可以看到,組合的過程,就是
- 先把list1的元素(
['A','B']
),append到result中
result = [['A'], ['B']]
- 把上面的result與list2中每個元素(
['C','D','E']
)做組合,再更新result
result = [['A', 'C'], ['A', 'D'], ['A', 'E'], ['B', 'C'], ['B', 'D'], ['B', 'E']]
- 如果還有list3,再進行2的過程
這裏有個小經驗,就是將多個list放入一個list中,就避免了for的個數不確定的問題。
最終,使用這段代碼,就解決了本文開頭提出的問題:
all_list = [['A', 'B'], ['C', 'D'], ['E','F','G'], ['H', 'I']]
result = [[]]
for pool in all_list:
tmp = []
for x in result:
for y in pool:
tmp.append(x+[y])
result = tmp
print(result)
使用itertools
上面的邏輯過程,已經被itertools做了更強大的實現,可以用更簡潔的代碼來解決問題:
import itertools
all_list = [['A', 'B'], ['C', 'D'], ['E','F','G'], ['H', 'I']]
list(itertools.product(*all_list))
注意,*all_list的用法,是爲函數傳入多個參數(不確定參數個數)的語法。
itertools很多源代碼都放到文檔中了,可以在[1]中查看itertools的很多方法源碼。
上面的代碼,其實就是itertools中product的部分源碼。
參考
- [1] https://docs.python.org/3/library/itertools.html