创建/访问/修改未指定维度的嵌套Python列表

2024-04-19 18:33:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我的一个API调用返回多维数据的dict。dict中的每一项都是一段数据,对应于表单的一个键

"index1:index2: ... :indexN"

这是一个由冒号分隔的整数字符串,它表示数据项出现在第一维度的位置index1,第二维度的位置index2,等等,直到第n维度的位置indexN。你知道吗

我想用这个数据字典来填充一个多维列表,以便进一步分析。理想情况下,这意味着迭代dict并将键解释为索引列表,即la

index_list = [int(i) for i in key.split(':')]

不幸的是,我正在自动执行几个相关(但不同)的API调用来填充一个数据包装类的几个不同实例,而且数据集不是固定维度的。因此,我不能硬编码这样的作业

data[index1][index2]...[indexN] = dict[key]

有没有一种Pythonic方法可以使用第二个列表作为索引值来创建、访问和修改多列表?“感觉像”的东西

data[*args] = dict[key]

args = index_list

也许(尽管这显然是无稽之谈的伪代码)?你知道吗


Tags: 数据keyapi表单列表dataindexargs
2条回答

这不是最优雅的方式,但这很管用:

def lookup(data, indices):
    if len(indices) == 1:
        return data[indices[0]]
    return lookup(data[indices[0]], indices[1:])

任务的工作方式相同:

def assign(data, indices, value):
    if len(indices) == 1:
        data[indices[0]] = value
    lookup(data[indices[0]], indices[1:])

编辑可能是一种更简洁的方法,使用不同于默认dict()的对象:

class MultiDict(dict):
    def __getitem__(self, key):
        item = super().__getitem__(key[0])
        if len(key) > 1:
            item = item[key[1:]]
        return item

    def __setitem__(self, key, value):
        if len(key) > 1:
            if key[0] not in self:
                super().__setitem__(key[0], MultiDict())
            super().__getitem__(key[0])[key[1:]] = value
        else:
            super().__setitem__(key[0], value)

    def __delitem__(self, key):
        if len(key) > 1:
            del super().__getitem__(key[0])[key[1:]]
        else:
            super().__delitem__(key[0])

    # Converts nested dicts recursively
    def dimensionalize(self):
        for key in self:
            item = super().__getitem__(key)
            if type(item) == dict:
                super().__setitem__(key, MultiDict(item))
                super().__getitem__(key).dimensionalize()
        return self

只需将嵌套的dict转换为MultiDict,然后直接用列表或元组对它们进行索引。例如:

b = MultiDict({1:{3:4}}).dimensionalize()

indices = (1,3)
print(b[indices])
# Prints 4

b[2,5] = 6
print(b[2,5])
# Prints 6

我不知道reduce是否是pythonic,但你可以简明扼要地说。一些样本数据,正方形尺寸:

In [1]: import numpy

In [2]: data = numpy.arange(32).reshape((2,2,2,2,2))

我们要用整数来表示,因为你知道如何拆分字符串。你知道吗

In [3]: nums = [0, 1, 1, 0, 1] # 1+4+8 = 13

In [4]: def getindex(x, i):
   ...:     return x[i]
   ...:
   ...:

简单地说:

In [5]: from functools import reduce

In [6]: def indexer(data, ix):
   ...:     return reduce(getindex, ix, data)
   ...:
   ...:

In [7]: indexer(data, nums)
Out[7]: 13

你可以用一个整洁的小班:

In [17]: def _to_nums(keys):
    ...:     return map(int, key.split(':'))
    ...:
    ...: class DataAccessor:
    ...:     def __init__(self, data):
    ...:         self.data = data
    ...:     def indexer(self, ix):
    ...:         return reduce(getindex, ix, self.data)
    ...:     def assign(self, key, value):
    ...:         *ix, last_index = _to_nums(key)
    ...:         lastdim = self.indexer(ix)
    ...:         lastdim[last_index] = value
    ...:     def select(self, key):
    ...:         return self.indexer(_to_nums(key))
    ...:

In [18]: accsr = DataAccessor(data)

In [19]: key = '0:1:0:1:1' # 1 + 2 + 8 = 11
In [20]: accsr.select(key)
Out[20]: 11

和任务:

In [21]: accsr.assign('1:1:1:1:1', 42)

In [22]: accsr.select('1:1:1:1:1')
Out[22]: 42

In [23]: data[0,1,0,1]
Out[23]: array([10, 42])

相关问题 更多 >