我试图将对象列表转换为嵌套的dict,可以通过索引访问.
以下代码适用于两级嵌套字典.我想将它扩展到灵活地工作任意数量的级别.
from collections import namedtuple
import pprint
Holding = namedtuple('holding', ['portfolio', 'ticker', 'shares'])
lst = [
Holding('Large Cap', 'TSLA', 100),
Holding('Large Cap', 'MSFT', 200),
Holding('Small Cap', 'UTSI', 500)
]
def indexer(lst, indexes):
"""Creates a dynamic nested dictionary based on indexes."""
result = {}
for item in lst:
index0 = getattr(item, indexes[0])
index1 = getattr(item, indexes[1])
result.setdefault(index0, {}).setdefault(index1, [])
result[index0][index1].append(item)
return result
d = indexer(lst, ['portfolio', 'ticker'])
pp = pprint.PrettyPrinter()
pp.pprint(d)
Run Code Online (Sandbox Code Playgroud)
输出:
{'Large Cap': {'MSFT': [holding(portfolio='Large Cap', ticker='MSFT', shares=200)],
'TSLA': [holding(portfolio='Large Cap', ticker='TSLA', shares=100)]},
'Small Cap': {'UTSI': [holding(portfolio='Small Cap', ticker='UTSI', shares=500)]}}
Run Code Online (Sandbox Code Playgroud)
您可以按照以下方式尝试。只需迭代索引指定的属性列表并继续跟踪由此创建的嵌套dict:
def indexer(lst, indexes):
result = {}
for item in lst:
attrs = [getattr(item, i) for i in indexes]
crnt = result # always the dict at the current nesting level
for attr in attrs[:-1]:
# follow one level deeper
crnt = crnt.setdefault(attr, {})
crnt.setdefault(attrs[-1], []).append(item)
return result
Run Code Online (Sandbox Code Playgroud)
这会产生以下输出:
>>> d = indexer(lst, ['portfolio', 'ticker'])
{'Large Cap': {'ticker': [holding(portfolio='Large Cap', ticker='TSLA', shares=100),
holding(portfolio='Large Cap', ticker='MSFT', shares=200)]},
'Small Cap': {'ticker': [holding(portfolio='Small Cap', ticker='UTSI', shares=500)]}}
>>> d = indexer(lst, ['portfolio', 'ticker', 'shares'])
{'Large Cap': {'MSFT': {200: [holding(portfolio='Large Cap', ticker='MSFT', shares=200)]},
'TSLA': {100: [holding(portfolio='Large Cap', ticker='TSLA', shares=100)]}},
'Small Cap': {'UTSI': {500: [holding(portfolio='Small Cap', ticker='UTSI', shares=500)]}}}
Run Code Online (Sandbox Code Playgroud)