天天看點

一道快速考察 Python 基礎的面試題等價于

一道快速考察 Python 基礎的面試題

這是前一陣子群友發在群裡的一道面試題,利用 Python 字典的特性,可以巧妙地使用精簡代碼達成完美解。

題目

将 data 轉換成 new_data 這種形式,寫出轉換過程。

data = {

'a_b_h':1,
'a_b_i':2,
'a_c_j':3,
'a_d':4,
'a_c_k':5,
'a_e':6           

}

new_data = {

'a':{
    'b':{
        'h':1,
        'i':2
    },
    'c':{
        'j':3,
        'k':5
    },
    'd':4,
    'e':6
}           

可以看出,轉換的過程是将 key 的下劃線進行拆分,然後下劃線後邊的字元嵌套在前面字元的值中。

感興趣就打開 IDE,自己先試着解一下。

解題思路

你應該很快想到,主要思路是将下劃線 split 後,然後依次使用字元生成内層字典,當達到最後一個字元時将數字作為值。

那麼關鍵點在于,如何不斷地獲得内層字典去修改呢?實際本題就是考察你是否了解 Python 字典是引用傳遞這個特性。

什麼是引用傳遞?我們知道 Python 中字典和清單對象都是可變對象,它們的變量傳遞給另一個變量後,改變對象元素會使得兩個變量都會同時改變,比如:

new_data = {}

tmp = {}

new_data['a'] = tmp

print(new_data) # {'a': {}}

tmp['b'] = 1

print(new_data) # {'a': {'b': 1}}

如上,利用這個特性,将内層字典指派給一個中間變量,然後改變這個中間變量,即可同步修改最終的 new_data 變量。

根據這個思路,初步代碼如下:

'a_b_h':1,
'a_b_i':2,
'a_c_j':3,
'a_d':4,
'a_c_k':5,
'a_e':6           

for key, value in data.items():

keys = key.split('_')
tmp = new_data
last = len(keys) - 1  # 最後一個 key 的索引值 
for i, k in enumerate(keys):
    if i == last:
        tmp[k] = value
        continue
    if k not in tmp:
        sub_tmp = {}
        tmp[k] = sub_tmp
        tmp = sub_tmp
    else:
        tmp = tmp[k]           

這也是群友給出的第一版答案,這樣寫并沒有多大問題,但是代碼比較繁瑣,肯定還有優化空間。

我們可以隻使用一個中間變量即可,進一步優化:

for field, value in data.items():

keys = field.split('_') 
tmp = new_data 
last = len(keys) - 1
for i, k in enumerate(keys): 
    if k not in tmp:
        tmp[k] = {} if i < last else value
    tmp = tmp[k]  # 将内層 dict 傳給 tmp           

上面這個代碼看似很簡潔了,但是仍然還有兩個 if 判斷,如果不是使用了三元表達式的話,還會更多行。

是以可以進一步優化:

keys = field.split('_') 
tmp = new_data 
for k in keys[:-1]: 
    tmp = tmp.setdefault(k, {})
tmp[keys[-1]] = value           

我們省略掉了 last 來判斷最後一個字元的索引,直接通過 keys[:-1] 避開最後一個字元,末尾再單獨生成數字鍵值對。

這裡還使用字典的一個内置方法 —— setdefault。

dict.setdefault(key, default=None) 方法和 get 方法類似,隻是如果鍵不存在于字典中,不僅會傳回 default 參數的值,還同時會用該值自動生成一個鍵值對。

if k not in tmp:

tmp[k] = {}           

v = tmp[k]

等價于

v = tmp.setdefault(k, {})

最終我們使用了 6 行代碼就解出該題,這也是接近最簡代碼。

如果使用字典引用的特性是合格的話,那麼當你用出 setdefault 這個方法後,面試官已經給你打了優秀,是以一定要熟悉這些資料對象的所有内置方法。

本文屬于原創,首發于微信公衆号「面向人生程式設計」,如需轉載請背景留言。

原文位址

https://my.oschina.net/u/4234347/blog/3164258

繼續閱讀