簡體   English   中英

如何建立一個動態增長的嵌套列表理解?

[英]How to build a dynamically growing nested list comprehension?

假設有以下代碼檢查數字的乘數是否等於輸入數字:

results = [a for a in range(10) if a == input]
results += [a*b for a in range(10) for b in range(10) if a*b == input]
results += [a*b*c for a in range(10) for b in range(10) for c in range(10) if a*b*c == input]
...

我希望更改它,以便在沒有找到結果的情況下繼續動態搜索匹配項。 所以:

  • 如果一位數字沒有結果,請繼續兩位數字
  • 如果兩位數沒有結果,請繼續輸入三位數
  • 等等 ...

我想以一種優雅的方式做到這一點,即使這種方式不太復雜,也可以采用單線方式。 如果根本沒有匹配項,我還需要一個中斷條件來避免無限循環。 例如,如果輸入的質數> 10,則沒有結果。 中斷條件應類似於:

if(math.pow(2, countOfDigits) > input):
    return

其中countOfDigits是嵌套列表countOfDigits中當前檢查的位數。 換句話說,我的初始示例的第一行代表countOfDigits == 1 ,第二行countOfDigits == 2和第三行countOfDigits == 3

哦,那就繼續:

next(
    sum(x) 
    for i in range(1, input) # overkill
    for x in itertools.product(range(10), repeat = i) 
    if reduce(operator.mul, x) == input
)

編輯:您已更改問題以返回乘積而不是總和,所以吐出input而不是sum(x)

我不確定您是否要進行第一個匹配,還是想要所有匹配都等於最小因子的匹配。 如果是后者,則可以通過將input, i從此迭代器中吐出,然后使用itertools.groupby根據元組中的第二個值來收集它們,然后僅取結果中的第一個值並進行迭代來實現它可以獲取所有匹配項(盡管,由於您現在輸出的input可能與長度無關,所以沒有意思)。

編輯:

您想要的是可以迭代的東西,但是直到盡可能晚才起作用。 那不是列表,因此列表理解是錯誤的工具。 幸運的是,您可以使用生成器表達式 您的代碼非常復雜,因此我們可能希望使用在標准庫itertools定義的一些幫助程序。

讓我們先看一下零件的一般情況:

[n

   for x0 in range(10) 
   for x1 in range(10)
   ...
   for xn in range(10) 

 if x0 * x1 * ... * xn == input]

我們可以歸納為三個部分。 我們將從嵌套的for循環開始,作為N的參數。為此,我們將使用itertools.product ,它需要一個序列序列,例如[range(10), range(10), ... , range(10)]並從這些序列中產生所有可能的項目組合。 在多次遍歷一個序列的特殊情況下,您可以將嵌套深度作為repeat傳遞,這樣我們就可以:

[n

   for x in itertools.product(xrange(10), repeat=n)

 if x[0] * x[1] * ... * x[n] == input]

對於輸出中的總和,我們可以使用sum()將其展平為單個值,對於乘積,實際上並沒有等效項。 我們可以用reduce做成一個函數,並將兩個數字相乘,這可以從另一個標准庫中獲得: operator.mul

(n
 for x in itertools.product(xrange(10), repeat=n)
 if reduce(operator.mul, x, 1) == input)

到目前為止,到目前為止,我們只需要對每個n值重復此內部部分。 假設我們要永遠搜索,我們可以使用itertools.count(1)獲得一個無窮無盡的數字序列,最后,我們只需要將此平坦的序列轉換為單個序列,就可以使用itertools.chain.from_iterable

itertools.chain.from_iterable(
     (n
      for x in itertools.product(xrange(10), repeat=n)
      if reduce(operator.mul, x, 1) == input)
     for n in itertools.count(1)
     if 2 ** n > input))
In [32]: input = 32

In [33]: next(itertools.chain.from_iterable(
        (n
         for x in itertools.product(xrange(10), repeat=n)
         if reduce(operator.mul, x, 1) == input)
        for n in itertools.count(1) if 2 ** n > input))
Out[33]: 6

我認為您不希望列表理解。 我認為發電機在這里會更好:

def generate(x):
    for digits in itertools.count(1):
        for i in itertools.product(range(1, 10), repeat=digits):
            if reduce(operator.mul, i) == x:
                yield i
    if (math.pow(2, digits) > x):
        break

然后,您for i in generate(input_number)做。

(您還需要from functools import reduce import itertools到頂部的from functools import reduceimport math )。

((math.pow(2,digits)> x)只是中斷條件。)

您有幾個序列,每個序列可能包含也可能不包含解決方案。 將它們轉換為生成器,使用itertools將序列“鏈接”在一起,然后詢問結果序列的第一個元素(請注意,不包含解決方案的序列將為空)。

首先,您需要一種為任何n生成n元組的序列的方法。 itertools模塊具有幾個功能,這些功能的效果可與嵌套的for循環相比。 與您的算法匹配的一個是itertools.product 以下生成所有n位元組:

tuples = itertools.product(range(10), repeat=n) 

使用itertools.combinations_with_replacement實際上更好,因為(4,5)(5,4)都沒有測試點。 它具有相似的語法。 所以這是一個生成器,它將為您提供無限個n元組序列,以增加n

sequences = ( itertools.product(range(10), repeat=n) for n in itertools.count(1) )

接下來,您想將序列串在一起(實際上尚未遍歷它們),成為一個序列。 由於這些是生成器,因此僅在需要時才對其進行評估。

bigchain = itertools.chain.from_iterable(sequences)

bigchain將吐出您需要檢查的所有元組。 為了測試它們,您需要一種將任意長度的元組相乘的方法。 讓我們定義一下:

def mytest(x):
    return reduce(operator.mul, x, 1) == target

現在,您可以使用此測試來“過濾”此序列,以僅選擇匹配的元組(由於組合中包含數字1 ,因此將總是有很多元組),然后請求第一個。

print itertools.islice(ifilter(mytest, bigchain), 1).next()     

我更改了代碼,以元組形式返回解決方案,因為否則,您會得到想要搜索的數字(例如32 ),但不會告訴您您不知道的任何內容!

這是一起:

from itertools import *
import operator

target = 32

sequences = ( combinations_with_replacement(range(10), n) for n in count(1) )
bigchain = chain.from_iterable(sequences)

def mytest(x):
    return reduce(operator.mul, x, 1) == target

print islice(ifilter(mytest, bigchain), 1).next()
# prints (4, 8)

您還可以消除上面的中間變量,並將所有內容組合為一個表達式。 但是有什么意義呢?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM