![](/img/trans.png)
[英]Convert nested list to dict where first element of list is key for dict
[英]Convert a list into a dict where each key is nested under the next one
我想轉換這個列表:
[1,2,3,4,5]
進入這個字典:
{ 1 :
{ 2 :
{ 3 :
{ 4 : 5 }}}}
這聽起來並不太復雜,但是當需要為比表面更深的鍵分配值時,我感到很困惑。 我有一個遞歸函數來查找我的字典有多深,但我不知道如何告訴我的算法“在此處添加新鍵”。
您正在尋找一個遞歸函數,該函數構建一個字典,其中第一個列表元素作為鍵,列表的其余部分作為值進行轉換:
l = [1, 2, 3, 4, 5]
def l2d(l):
if len(l) < 2: # Not good
raise Exception("The list is too short")
if len(l) == 2: # Base case
return {l[0]: l[1]}
# Recursive case
return {l[0]: l2d(l[1:])}
l2d(l)
# {1: {2: {3: {4: 5}}}}
另一個有趣的方法是使用functools.reduce
:
from functools import reduce
reduce(lambda tail,head: {head: tail}, reversed(l))
# {1: {2: {3: {4: 5}}}}
它逐步將字典構造函數應用於列表的第一個元素和其余元素。 列表先倒序,所以構造自然從最后開始。 如果列表太短,函數會返回它的第一個元素,這可能是也可能不是。
“減少”解決方案要快得多,大約兩個數量級。 底線:避免遞歸。
不需要遞歸來解決這個問題。 一個簡單的循環就足夠了。
def nest(keys):
if not keys:
return {}
elif len(keys) == 1:
return key[0]
root = level = {}
for key in keys[:-1]:
level[key] = {}
level = level[key]
level[key] = keys[-1]
return root
或者,您可以從內到外構建 dict:
def nest(keys):
if not keys:
return {}
current = keys[-1]
for key in keys[-2::-1]: # iterate keys in reverse
current = {key: current}
return current
這是使用遞歸邏輯直到列表長度為 1 的好方法。例如:
更新:修復空列表錯誤。
A = [1, 2, 3, 4, 5]
def rec_dict(listA):
try:
if len(listA) <= 1:
listA = listA[0]
else:
listA = {listA.pop(0): rec_dict(listA)}
except IndexError:
pass
return listA
print(rec_dict(A))
返回:
{1: {2: {3: {4: 5}}}}
我想使用不同的方法提出另一種選擇:
雖然不推薦使用ast.literal_eval
,但我認為在這種情況下可能會有用。 此外,您可以使用re.sub()
+ re.findall()
幫助自己找到匹配項並正確進行替換。 這里的想法是使用列表的字符串表示。
import ast
import re
lst = [1, 2, 3, 4, 5]
lst_str = str(lst).replace("[","{").replace("]","}")
pattern_commas = re.compile(", ")
matches = re.findall(pattern_commas, lst_str)
n = len(matches) - 1
output = re.sub(pattern_commas, ':{', lst_str, n).replace(",",":") + '}' * n
dictionary = ast.literal_eval(output)
print(dictionary)
輸出:
{1: {2: {3: {4: 5}}}}
編輯:在使用此答案之前,請閱讀@wjandrea 的評論。 這不適用於所有輸入。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.