Python从键列表生成动态字典

8

我有一个如下的列表:

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"]
value1 = "Roger"

我该如何生成动态字典,并按照以下方式检索 -

mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value

这个列表可以是任何东西; 可变长度或由我不知道的“N”个元素组成...

现在我有另一个列表,因此我的字典应相应更新

keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"]
value2 = 25

即,如果已经存在"Person"、"Male"、"Boy"、"Student"、"id_123"这些键值,新的键"age"应该被添加...

我建议将列表中的所有项附加在一起,并使用结果字符串作为键。这样会更容易。 - rajpy
这个问题的答案可能会有所帮助:https://dev59.com/f3HYa4cB1Zd3GeqPPMD1 - DJG
7个回答

8

我刚开始学习Python,所以我的代码可能不太符合Python的规范,但这是我的代码:

d = {}

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"]
keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"]
value1 = "Roger"
value2 = 3

def insert(cur, list, value):
    if len(list) == 1:
        cur[list[0]] = value
        return
    if not cur.has_key(list[0]):
        cur[list[0]] = {}
    insert(cur[list[0]], list[1:], value)

insert(d, keyList1, value1)
insert(d, keyList2, value2)

{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 3, 'Name': 'Roger'}}}}}}

1
这最终与我的解决方案非常相似。一个简单的建议:尽可能避免使用.has_key;更喜欢更快和更易理解的if list[0] not in cur - nneonneo
谢谢,我同意它更可读,而且可读性很重要,但为什么它更快呢? - Roman Pekar
2
使用 timeit 进行测试。在我的电脑上,in.has_key 快两倍(0.0672微秒对0.117微秒)。.has_key 是一种方法查找,而 in 是一个内置函数,其分派速度更快。 - nneonneo
.has_key在Python3中已被弃用且不存在。 - John La Rooy

4
您可以通过创建嵌套的defaultdict来实现此目的:
from collections import defaultdict

def recursive_defaultdict():
    return defaultdict(recursive_defaultdict)

def setpath(d, p, k):
    if len(p) == 1:
        d[p[0]] = k
    else:
        setpath(d[p[0]], p[1:], k)

mydict = recursive_defaultdict()

setpath(mydict, ["Person", "Male", "Boy", "Student", "id_123", "Name"], 'Roger')

print mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"]
# prints 'Roger'

这具有很好的优势,可以进行编写。
mydict['a']['b'] = 4

您可以不必使用setpath辅助程序来实现。

您也可以不使用递归defaultdict

def setpath(d, p, k):
    if len(p) == 1:
        d[p[0]] = k
    else:
        setpath(d.setdefault(p[0], {}), p[1:], k)

3
也许你可以创建字典的子类:
class ChainDict(dict):
    def set_key_chain(self, keyList, value):
        t = self
        for k in keyList[:-1]:
            t = t.setdefault(k, {})
        t.setdefault(keyList[-1], value)

c = ChainDict()
c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Name'], 'Roger')
print c
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Name': 'Roger'}}}}}}

c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Age'], 25)
print c
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 25,
      'Name': 'Roger'}}}}}}

1
创建一个继承自dict的类,其中init方法接受一个列表和一个单一值作为输入,并通过迭代列表将键设置为该值,定义一个update方法,该方法接受一个列表和一个新值,并为尚未成为键的每个项目设置它们为新值(假设这是您需要的)。不要考虑使用"mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value1"这样的子索引方式,因为它会导致混淆。保留html标签。

0

我正在尝试处理类似的东西,所以我可以提供一些指导方针,但是我在Python方面很幼稚,所以这只是一个指南...

你有一个键列表,所以你肯定可以从循环开始迭代每个值,然后分配该值

例如:

for i in keylist:
if type(keylist[i]) == dict:
        do something
    else:
        keylist[i] = {}

在做某事时,您需要增加i并将索引更改为[i] [i + 1],然后一直遵循相同的方式,直到i + n = len(keylist)


0

使用tuple(keyList1)作为键。(元组是不可变的,因此可以成为字典键)。

使用嵌套字典方法会让你头疼不已。(枚举时需要嵌套循环,当层次结构需要更改时存在遗留数据等问题)。

仔细想想,也许你应该定义一个人类。

class Person(object):
    gender = "Male"
    group = "Student"
    id = 123
    Name = "John Doe"

然后使用所有人的列表,并使用例如筛选器进行过滤。

male_students = [s for s in  ALL_PERSONS where s.gender=="Male" and s.group="Student"]

...对于不超过10000名学生,您的性能应该是可以接受的。


-2
>>> mydict = {}
>>> keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"]
>>> value1 = "Roger"
>>> reduce(lambda x, y: x.setdefault(y, {}), keyList1, mydict)
{}
>>> mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value1

你也可以像这样一步完成

>>> keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"]
>>> value2 = 25
>>> reduce(lambda x,y: x.setdefault(y,{}), keyList2[:-1], mydict).update({keyList2[-1]: value2})

mydict {'Person': {'Male': {'Boy': {'Student': {'id_123': {'Name': 'Roger'}}}}}}
- Steve Barnes
@AbhishekKulkarni,嗯...reduce(lambda x, y: x.setdefault(y, {}), keyList1, mydict)取决于元素数量还是特定键的位置? - John La Rooy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接