簡體   English   中英

無法在Python中使用遞歸從嵌套列表中刪除項目

[英]Cannot remove item from nested list using recursion in Python

如標題所述。 我正在嘗試使用遞歸遍歷列表,並刪除列表中包括給定數字的任何數字(包括嵌套列表)。 這是我到目前為止的內容:

def deepRemoveAll(e, L):
    if len(L) == 0:
        return L
    if type(L[0]) == type([]):
        return deepRemoveAll(e, L[0])
    if e == L[0]:
        L.pop(0)
        return deepRemoveAll(e, L)
    if e != L[0]:
        temp = L[0]
        L.pop(0)
        return [temp] + deepRemoveAll(e, L)

print(deepRemoveAll(47, [42, 47, [1, 2, [47, 48, 49], 50, 47, 51], 52]))

代碼對我來說似乎完美無缺,但是由於某種原因,該函數返回了列表[42,1,2,48,49]。 這是不正確的,因為在這種情況下,我需要刪除的只是其中包含的所有47,但同時也刪除了50、51和52。嵌套列表也需要保持原樣,但這將所有內容組合為一個,我不能刪除我的生活弄清楚為什么。

這應該有助於:

def deep_remove_all(e, a_list):
    res = []
    for item in a_list:
        if isinstance(item, list):
            res.append(deep_remove_all(e, item))
        elif item != e:
            res.append(item)
    return res

您也可以這樣寫:

def deep_remove_all(e, a_list):
    res = []
    for item in a_list:
        if item == e:
            continue

        res.append( 
            deep_remove_all(e, item)
            if isinstance(item, list) 
            else item
        )

    return res

看這兩行:

if type(L[0]) == type([]):
    return deepRemoveAll(e, L[0]);

您在這里說的是:

如果列表的第一個元素是列表,則在該列表上遞歸並丟棄該列表的其余元素。

例如,如果您有L=[[1,2],3]if type(L[0]) == type([])檢查將返回true,並且您會說deepRemoveAll(e, [1,2]) ,無論e是什么,3都不見了。

要修復您的代碼:

只需更改return deepRemoveAll(e, L[0]); L[0] = deepRemoveAll(e, L[0]) ,以便列表的第一個元素變成自身,而所有47都被刪除,然后繼續其余的邏輯。

讓我們看一下您的代碼,找到一些要修復的東西:

def deepRemoveAll(e, L):
    if len(L) == 0:
            return L;
    if type(L[0]) == type([]):
            return deepRemoveAll(e, L[0]);
    if e == L[0]:
            L.pop(0);
            return deepRemoveAll(e, L);
    if e != L[0]:
            temp = L[0];
            L.pop(0);
            return [temp] + deepRemoveAll(e, L);

print(deepRemoveAll(47, [42, 47, [1, 2, [47, 48, 49], 50, 47, 51], 52]));

我看到的第一件事只是一個小問題: type([]) 在現代Python中,這就是list

但是在我們更改它之前,我注意到您正在使用L[0]做很多事情,並且幾乎總是pop它。 讓我們變得常見:

def deepRemoveAll(e, L):
    if len(L) == 0: return L

    l0 = L.pop(0)

現在我們有了l0(因此不再重復索引)了。 我們可以決定是否放回它。

if type(l0) == list:

這將修復上面的type([]) 但是,如果第一個元素是子列表,我們該怎么辦? 顯然,我們用第一個元素的深化版本替換了第一個元素:

if type(l0) == list:
    l0 = deepRemoveAll(e, l0)

它仍然將是第一個元素,但是現在我們知道它是干凈的。

下一步是檢查l0是否是我們要刪除的e 如果是這樣, 則無需替換列表的開頭-您只需返回清理后的余數即可。 沒錯,並且作為子列表也是互斥的,因此我們可以使用elseelif

elif l0 == e:
    return deepRemoveAll(e, L)

最后,有l0 != e 在這種情況下,我們要清潔其余的L,並將l0值重新貼在前面。

可是等等! 在l0是列表的情況下,這也是我們想要做的,還記得嗎? 到目前為止,我們所做的只是清除l0。

因此,讓我們脫離if / elif,以便可以將頂部代碼(l0是一個列表)與我們未放入的else代碼合並:l0!= e。

return [l0] + deepRemoveAll(e, L)

總結一下:

def deepRemoveAll(e, L):
    if len(L) == 0: return L

    l0 = L.pop(0)

    if type(l0) == list:
        l0 = deepRemoveAll(e, l0)
    elif l0 == e:
        return deepRemoveAll(e, L)

    return [l0] + deepRemoveAll(e, L)

暫無
暫無

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

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