簡體   English   中英

Python遞歸示例說明

[英]Python Recursive Example Explanation

所以目前正在線上通過麻省理工學院的OpenCourseWare計算機科學課程,我無法理解其中一個遞歸的例子。

def f(L):
    result = []
    for e in L:
        if type(e) != list:
            result.append(e)
        else:
            return f(e)
return result

當給出以下輸入時:

print f([1, [[2, 'a'], ['a','b']], (3, 4)])

輸出是:

[2, 'a']

我無法理解這個函數是如何工作的,或者它在做什么。 該函數最終不應該將每個字符串或int添加到結果列表中嗎? 我只是需要幫助,試圖了解這個功能如何“結束”和“解除”

我覺得輸出應該是:

[1,2,'a','a','b',3,4]

任何幫助將不勝感激!

函數f返回它遇到的第一個平面列表的(淺) 副本以及深度優先搜索

為什么? 那么首先讓我們來看看基本情況包含列表清單。 [1,'a',2,5] 在這種情況下, if語句將始終成功,因此e所有元素將添加到result並返回result

那么遞歸案例呢? 這意味着一個列表中的元素。 例如[1,['a',2],5] 現在對於第一個元素, if成功,因此將1添加到result列表中。 但是對於第二個元素['a',2]if 失敗了 這意味着我們使用['a',2]f執行遞歸調用。 現在,由於該列表不包含任何子列表,我們知道它將返回該列表的副本。

但請注意,我們會立即return該遞歸調用的結果。 因此,從我們采用else分支的那一刻起, result不再重要了:我們將返回f(e)返回的內容。

如果我們做出假設,我們就無法構造一個無限深的子列表循環(實際上我們可以,但在這種情況下我們將獲得堆棧溢出異常),我們最終將獲得一個平面列表並獲得該副本。

示例 :如果我們采用您的樣本輸入[1, [[2, 'a'], ['a','b']], (3, 4)] 我們可以追蹤電話。 所以我們首先在該列表上調用f ,它將生成以下“跟蹤”:

# **trace** of an example function call
f([1, [[2, 'a'], ['a','b']], (3, 4)]):
    result = []
    # for 1 in L:
    # if type(1) == list: # fails
    # else
    result.append(1) # result is now [1]
    # for [[2,'a'],['a','b']] in L:
    # if type([[2,'a'],['a','b']]) == list: succeeds
    return f([[2,'a'],['a','b']])
                      result = []
                      # for [2,'a'] in L:
                      # if type([2,'a']) == list: succeeds
                      return f([2,'a'])
                                        result = []
                                        # for 2 in L:
                                        # if type(2) == list: fails
                                        # else:
                                        result.append(2) # result is now [2]
                                        # for 'a' in [2,'a']:
                                        # if type('a') == list: fails
                                        # else:
                                        result.append('a') # result is now [2,'a']
                                        return [2,'a']
                      return [2,'a']
    return [2,'a']

展平

如果您想要壓縮列表而不是返回第一個平面列表,則可以將代碼重寫為:

def f(L):
    result = []
    for e in L:
        if type(e) != list:
            result.append(e)
        else:
            result += f(e)
    return result

請注意,這只會壓縮list (甚至不是list的子類)。

所以根據你建議的答案,我看到你了解代碼的概念。 它越陷越深,直到找到一個元素。 但是看看上層的后退步驟:

當它第一次到達最深點時([2,'a']列表的元素),它在這個級別上完成循環並返回結果2和a。 這是一個RETURN語句...這意味着循環是停止的,因此沒有找到其他元素。

現在懸而未決的問題是,為什么它沒有顯示1作為結果的一部分? 出於同樣的原因,RETURN是較低級別(2,a)和較高級別結果的結果。 如果將“result”更改為全局變量,結果將為[1,2,'a']

最好的祝福

當運行到第一個自底向下的list-element(不包含列表)時,作為發布的函數返回/退出 - 這可以防止遍歷遞歸的所有其他分支。 例如:

print( f([1, [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)]) )
# gives: [4, 'c']
print( f([1, ['X','Y'], [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)]) )
# gives: ['X','Y']

導致此行為的關鍵點是該行

result = [] 

這會將列表重置,並將每次調用函數的結果重置為空列表。 這樣,只有一個項目從遞歸調用鏈中返回。

順便說一句,下面的函數f做了你所期望的,不是嗎?

def f(L, result):
    for e in L:
        if type(e) != list:
            result.append(e)
        else:
            f(e, result)

result=[]; f([1, [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)], result) print( result )
# gives: [1, 2, 'a', 3, 'b', 4, 'c', 'a', 'b', (3, 4)]
result=[]; f( [1, ['X','Y'], [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)], result); print( result )
# gives: [1, 'X', 'Y', 2, 'a', 3, 'b', 4, 'c', 'a', 'b', (3, 4)]

注意:(3,4)是TUPLE而不是列表......

如果這些項目本身不是列表,則上述函數f從列表中收集項目。 在特殊情況下,當列表中的項目是列表時,該函數會調用自身來從此列表中收集項目。 通過這種方式,無論人們需要挖掘多深,每一個元素都會被收集到層次結構中。 這是遞歸的美妙 - 一個函數調用自己做了訪問所有分支和他們的葉子在樹下的“魔力”:)

暫無
暫無

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

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