【问题标题】:Which data structure to use as an array of dicts?哪个数据结构用作字典数组?
【发布时间】:2013-03-10 13:24:19
【问题描述】:

我需要构建一个像这样的数据结构:

{
    key: {k: v for k in range(fixed_small_number)}
    for key in range(fixed_large_number)
}

问题是我正在以一种“折衷”的方式构建它,每次多获取一个项目以放入随机 k 作为随机密钥,即我需要随机访问,并且我需要内部 dict是可变的。

所以我的问题分为两个:

  1. 外部字典的推荐类型。

  2. 内部字典的推荐类型。

对我来说“最好”的解决方案是一组可变的命名元组,只是这个不存在。

我可以使用一个命名元组列表,然后用新数据重新创建每个,但这听起来非常浪费,因为列表不具备随机访问效率,而且所有数据都需要重写。

是否有一些我不知道的神奇新结构?

编辑: 使用示例:

for key, k, v in [('a', 1, 2), ('b', 1, 3), ('a', 2, 1), ('a', 3, 1), ('b', 3, 1) ...]:
    my_structre[key][k] = v

编辑2:

事实证明,列表实际上 DO support random access

【问题讨论】:

  • 如果我正确理解了这个问题,我不确定这是否可行。 dicts 等可变对象不能是字典键。
  • 无论如何,目前尚不清楚您要完成什么。您能否举例说明如何“折衷地”构建此数据结构? IE。给定单个更新的之前和之后状态?
  • 我不确定我是否理解.. 我在哪里建议 dicts 将用作键?
  • v 来自哪里?
  • @phistakis 嵌套的字典理解? TBH 从一开始它看起来不像是有效的 Python,您应该真正扩展您的代码示例以显示您正在尝试做什么。也许写出实际的虚拟数据?

标签: python arrays list namedtuple


【解决方案1】:

您可以构建一个自定义类,使用__slots__ 来限制使用的内存量:

class MutableEfficientNamedList(object):
    __slots__ = ('field1', 'field2', 'field3')

    def __init__(self, *values):
        for k, v in zip(self.__slots__, values):
            setattr(self, k, v)

    def __getitem__(self, i):
        return getattr(self, self.__slots__[i])

    def __setitem__(self, i, v):
        return setattr(self, self.__slots__[i], v)

    def __repr__(self):
        return '{}({})'.format(type(self).__name__, 
            ', '.join(repr(getattr(self, s)) for s in self.__slots__))

然后在你的结构中使用它们。它们可以像命名元组一样使用(允许按索引按名称访问),但它们允许变异。通过使用__slots__,每个实例的内存占用仍然很低:

>>> menl = MutableEfficientNamedList('foo', 'bar', 'baz')
>>> menl
MutableEfficientNamedList('foo', 'bar', 'baz')
>>> menl.field1
'foo'
>>> menl[0]
'foo'
>>> menl[1]
'bar'
>>> menl[1] = 'spam'
>>> menl.field2
'spam'

您当然要给插槽起有意义的名称,并且请为您的班级选择一个比我在示例中使用的名称更好的名称。 :-)

为了扩展namedtuple() 模式,这里是一个通用工厂函数:

def namedlist(name, *attrs):
    """Create a named list class named `name` with attributes `attrs`.
       `attrs` must be strings representing valid Python identifiers.
    """
    class MutableEfficientNamedList(object):
        __slots__ = attrs

        def __init__(self, *values):
            for k, v in zip(self.__slots__, values):
                setattr(self, k, v)

        def __getitem__(self, i):
            return getattr(self, self.__slots__[i])

        def __setitem__(self, i, v):
            return setattr(self, self.__slots__[i], v)

        def __repr__(self):
            return '{}({})'.format(type(self).__name__, 
                ', '.join(repr(getattr(self, s)) for s in self.__slots__))

    MutableEfficientNamedList.__name__ = name
    return MutableEfficientNamedList

MyList = namedlist('MyList', 'foo', 'bar', 'baz')
nl = MyList(1, 2, 3)
print nl  # MyList(1, 2, 3)
print nl.bar  # 2
print nl[1]  # 2

【讨论】:

  • __slots__ = ['field{}'.format(i+1) for i in xrange(3)](有更多字段时有用)
  • @nneonneo:那时我应该使用foobarbaz 作为字段名称;它们是说明性的。
【解决方案2】:

defaultdict 感觉就在这里:

from collections import defaultdict

d = defaultdict(lambda: defaultdict(int))

d[3][4] = 10

如果您想要固定大小的列表,defaultdict 可以满足您的需求:

d = defaultdict(lambda: [None]*fixed_small_number)

d[3][4] = 10
# d[3] is now [None, None, None, None, 10, None, None, ...]

【讨论】:

    【解决方案3】:

    举个例子:

    for key, k, v in [('a', 1, 2), ('b', 1, 3), ('a', 2, 1), ('a', 3, 1), ('b', 3, 1) ...]:
        my_structre[key][k] = v
    

    解决方案确实是使用defaultdict

    from collections import defaultdict
    
    d = defaultdict(dict)
    for key, k, v in [('a', 1, 2), ('b', 1, 3), ('a', 2, 1), ('a', 3, 1), ('b', 3, 1)]:
        d[key][k] = v
    

    答案:

    {'a': {1: 2, 2: 1, 3: 1}, 'b': {1: 3, 3: 1}}
    

    作为一个函数:

    def method(iter_of_3_item_iters):
        d = defaultdict(dict)
        for (a, b, c) in iter_of_3_item_iters:
            d[a][b] = c
        return d
    

    【讨论】:

      猜你喜欢
      • 2016-06-21
      • 1970-01-01
      • 2021-01-12
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      • 2011-01-01
      • 2023-04-08
      • 1970-01-01
      相关资源
      最近更新 更多