【问题标题】:Creating/accessing/modifying nested Python lists of unspecified dimension创建/访问/修改未指定维度的嵌套 Python 列表
【发布时间】:2018-07-17 07:17:56
【问题描述】:

我的一个 API 调用返回一个多维数据的字典。 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

也许(尽管这显然是无意义的伪代码)?

【问题讨论】:

  • 你误用了dict 这个名字,造成了很多混乱。请把它改成另一个名字。作为带有冒号注释的字符串,您所拥有的只是一个字符串。这里没有dict
  • 不,它是一个字典。用冒号注释的字符串是与字典中的数据条目相对应的键。 dict 看起来像数百个 {"index1:index2:...:indexN" : data_val} 条目
  • @MichaelCromer,不,您的帖子中没有定义任何字典。请提供 minimal reproducible example
  • @jpp 这是真的,但与最初的评论无关。我会提供一个 MWE,但是您如何编写一个工作示例来展示您所询问的编程概念的存在?我不能为我不知道的事情写一个“工作示例”;这就是问题的目的。 将如何编写 MWE?
  • An API call of mine returns a dict of multi-dimensional data. 开头为什么不打印此内容的摘录?然后在您的问题中明确定义它。喜欢my_dict = {1: 'adsfasdf', 2: 'fsgsd'}

标签: python python-3.x dictionary multidimensional-array


【解决方案1】:

这不是最优雅的方式,但这很有效:

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

只需将嵌套的dicts 转换为MultiDicts,然后使用列表或元组直接索引它们。例如:

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

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

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

【讨论】:

  • 这也是我最初的想法...如果没有更好的答案,我会接受这是正确的...
  • @MichaelCromer 更新了更清洁的使用方式。
【解决方案2】:

我不知道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])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多