1. 程式人生 > 程式設計 >使用 yield 壓平多層巢狀字典列表混合資料

使用 yield 壓平多層巢狀字典列表混合資料

在上一篇文章裡面,我們講到了如何使用Python的yield關鍵字簡化程式碼,壓平多層巢狀字典的。

那麼如果我們的資料不僅僅有字典,還有列表,是一個字典列表多層巢狀的資料怎麼辦呢?例如:

nest_dict = {
    'a': 1,'b': {
        'c': 2,'d': 3,'e': {'f': 4}
    },'g': {'h': 5},'i': 6,'j': {'k': {'l': {'m': 8}}},'n': [1,{'o': 1,'p': [1,2,3],'q': {'r': {'s': 100}}},3,[1,5]
}
複製程式碼

現在,請停下來,敲一敲程式碼,想想如何把處理列表的邏輯新增進去。

首先,我們來看一下最終被壓平以後的資料長什麼樣:

{'a': 1,'b_c': 2,'b_d': 3,'b_e_f': 4,'g_h': 5,'j_k_l_m': 8,'n_0': 1,'n_1_o': 1,'n_1_p_0': 1,'n_1_p_1': 2,'n_1_p_2': 3,'n_1_q_r_s': 100,'n_2': 3,'n_3_0': 1,'n_3_1': 2,'n_3_2': 3,'n_4': 5}
複製程式碼

對於'n': ['a','b','c']這種形式的資料,我們把它轉換為: {'n_0': 'a','n_1': 'b','n_2': 'c'}

我們原來的核心程式碼是這樣的:

def flat(x):
    for key,value in x.items():
        if isinstance(value,dict):
            for k,v in flat(value):
                k = f'{key}_{k}'
                yield (k,v)
        else:
            yield (key,value)
複製程式碼

你的第一反應,是不是這樣修改程式碼:

def flat(x):
    for key,v)
        elif isinstance(value,list):
            "一大堆處理列表的程式碼"
else: yield (key,value) 複製程式碼

如果你使用return和遞迴,你可能確實需要這樣寫。

但如果你使用yield關鍵字,那麼,你雖然也要修改程式碼,可是修改的地方卻不是這裡。我們要修改的地方在for key,value in x.items()

因為.items()這個方法是字典的方法,列表沒有這個方法。所以我們需要寫一個通用的迭代生成器,支援字典和列表,所以我們增加一個函式:iter_x:

def iter_x(x):
    if isinstance(x,dict):
        for key,value in x.items():
            yield (key,value)
    elif isinstance(x,list):
        for index,value in enumerate(x):
            yield (index,value)
複製程式碼

現在,我們在原來的程式碼中呼叫這段個新的生成器函式:

def flat(x):
    for key,value in iter_x(x):
        if isinstance(value,(dict,list)):
            for k,value)
複製程式碼

其中,isinstance(value,list)),相當於isinstance(value,dict) or isinstance(value,list)

我們來看一下執行效果:

掌握yield關鍵字,你的程式設計思路和想問題的方式會發生一個重大的轉變。