[英]recursive function for extract elements from deep nested lists/tuples
我想編寫一個從深層嵌套元組和列表中提取元素的函數,比方說我有這樣的東西
l = ('THIS', [('THAT', ['a', 'b']), 'c', ('THAT', ['d', 'e', 'f'])])
我想要一個沒有'THIS'和'THAT'的平面列表:
list = ['a', 'b', 'c', 'd', 'e', 'f']
這是我到目前為止所擁有的:
def extract(List):
global terms
terms = []
for i in word:
if type(i) is not str:
extract(i)
else:
if i is not "THIS" and i is not "THAT":
terms.append(i)
return terms
但我一直得到list = ['d', 'e', 'f']
,看起來在循環到'c'
之后再次設置了terms = []
。
你正在函數頂部執行terms = []
,所以當然每次遞歸調用函數時,你都會再次執行這些terms=[]
。
最快的解決方案是編寫一個簡單的包裝器:
def _extract(List):
global terms
for i in word:
if type(i) is not str:
_extract(i)
else:
if i is not "THIS" and i is not "THAT":
terms.append(i)
return terms
def extract(List):
global terms
terms = []
return _extract(List)
還有一件事:你不應該使用is
來測試字符串相等性(除非是非常非常特殊的情況)。 這測試它們在內存中是相同的字符串對象 。 它會發生在這里,至少在CPython中(因為兩個"THIS"
字符串都是同一模塊中的常量 - 即使它們不是,它們也會被intern
) - 但這不是你想要依賴的東西。 使用==
,它測試它們都意味着相同的字符串,無論它們是否實際上是相同的對象。
測試身份類型更常用,但通常不是你想要的。 實際上,您通常甚至不想測試類型是否相等 。 你經常沒有str
子類 - 如果你這樣做了,你可能想把它們視為str
(因為這是子類型的全部要點)。 對於你經常進行子類化的類型來說,這一點更為重要。
如果你還沒有完全理解所有這些,那么簡單的指導就是永遠不要使用is
除非你知道你有充分的理由。
所以,改變這個:
if i is not "THIS" and i is not "THAT":
......對此:
if i != "THIS" and i != "THAT":
或者,也許更好的(肯定更好,如果你有,比如說,四根弦檢查,而不是兩個),使用一組成員資格測試,而不是and
荷蘭國際集團一起多重考驗:
if i not in {"THIS", "THAT"}:
同樣,改變這個:
if type(i) is not str:
......對此:
if not isinstance(i, str):
但是,雖然我們在這里全部運作,為什么不使用閉包來消除全局?
def extract(List)
terms = []
def _extract(List):
nonlocal terms
for i in word:
if not isinstance(i, str):
_extract(i)
else:
if i not in {"THIS", "THAT"}:
terms.append(i)
return terms
return _extract(List)
這不是我解決這個問題的方式(如果給出這個規范並告訴他用遞歸來解決它,那么我的回答可能就是我所做的),但這有保留(和大部分的)精神的優點。實施)您現有的設計。
將“扁平化”和“過濾”的問題分開是很好的。 解耦代碼更易於編寫且更易於測試。 所以讓我們先用遞歸寫一個“flattener”:
from collections import Iterable
def flatten(collection):
for x in collection:
if isinstance(x, Iterable) and not isinstance(x, str):
yield from flatten(x)
else:
yield x
然后提取和黑名單:
def extract(data, exclude=()):
yield from (x for x in flatten(data) if x not in exclude)
L = ('THIS', [('THAT', ['a', 'b']), 'c', ('THAT', ['d', 'e', 'f'])])
print(*extract(L, exclude={'THIS', 'THAT'}))
假設可以忽略每個元組的第一個元素,並且我們應該使用作為第二個元素的列表進行遞歸,我們可以這樣做:
def extract(node):
if isinstance(node, tuple):
return extract(node[1])
if isinstance(node, list):
return [item for sublist in [extract(elem) for elem in node] for item in sublist]
return node
列表理解有點密集,這里與循環相同:
def extract(node):
if isinstance(node, tuple):
return extract(node[1])
if isinstance(node, list):
result = []
for item in node:
for sublist in extract(item):
for elem in sublist:
result.append(elem)
return result
return node
這個迭代函數應該與.extend()
列表運算符一起完成。
def func(lst):
new_lst = []
for i in lst:
if i != 'THAT' and i != 'THIS':
if type(i) == list or type(i) == tuple:
new_lst.extend(func(i))
else: new_lst.append(i)
return new_lst
l = ('THIS', [('THAT', ['a', 'b']), 'c', ('THAT', ['dk', 'e', 'f'])])
print(func(l))
['a','b','c','dk','e','f']
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.