首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从对象列表创建动态级别嵌套dict?

从对象列表创建动态级别嵌套dict?
EN

Stack Overflow用户
提问于 2017-12-26 21:09:37
回答 5查看 2.6K关注 0票数 8

我正在尝试将一个对象列表转换为一个嵌套的dict,索引可以访问它。

以下代码适用于两级嵌套字典。我想把它扩大到任何级别的灵活工作。

代码语言:javascript
复制
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)

产出:

代码语言:javascript
复制
{'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)]}}
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2017-12-26 21:27:28

你可以从以下几个方面来尝试。只需迭代索引指定的attribtes列表,并继续跟踪由此创建的嵌套dict

代码语言:javascript
复制
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 

这产生了下列产出:

代码语言:javascript
复制
>>> 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)]}}}
票数 1
EN

Stack Overflow用户

发布于 2017-12-26 23:27:05

实现嵌套字典的最好方法之一是Aaron的回答 to the implement 实现嵌套字典的最佳方法是什么?。这是一个在自生化编程语言中实现名为“Perl”的类型的示例。

无论如何,在这里使用一个是有用的,因为它意味着您只需要调用setdefault()来获取类似树的数据结构的“叶子”(这是list的,而不是子词典)。

因此,这里有一个你的问题的答案,利用它:

代码语言:javascript
复制
from collections import namedtuple
from functools import reduce
from operator import attrgetter
from pprint 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. """

    class Vividict(dict):
        """ dict subclass which dynamically creates sub-dictionaries when
            they're first referenced (and don't exist).
            See https://stackoverflow.com/a/19829714/355230
        """
        def __missing__(self, key):
            value = self[key] = type(self)()
            return value

    result = Vividict()
    index_getters = attrgetter(*indexes)
    for item in lst:
        *indices, leaf = index_getters(item)  # Leaves are lists, not dicts.
        target = reduce(lambda x, y: x[y], indices, result)
        target.setdefault(leaf, []).append(item)

    return result

d = indexer(lst, ['portfolio', 'ticker'])
pprint(d)
print()
d = indexer(lst, ['portfolio', 'ticker', 'shares'])
pprint(d)

输出:

代码语言:javascript
复制
{'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)]}}

{'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)]}}}
票数 3
EN

Stack Overflow用户

发布于 2017-12-26 21:33:45

您的代码实际上是一个很好的尝试,我所做的小的补充就是维护上一个索引引入的当前映射,并让下一个索引在其中创建一个映射。因此,对于每个索引(以及循环中的每一次迭代),您实际上都要走得更深。在最后一层,创建一个列表而不是字典,循环之后,项目被简单地附加到当前级别。

代码语言:javascript
复制
def indexer(lst, indexes):
    result = {}
    for item in lst:
        current_level = result
        for i, index in enumerate(indexes):
            key = getattr(item, index)
            current_level.setdefault(key, [] if i == len(indexes)-1 else {})  # if we are in the last iteration, create a list instead of a dict
            current_level = current_level[key]
        current_level.append(item)
    return result
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47983728

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档