假设我有一个嵌套列表(ndlist
),类似于任意维度的N-D数组(设ndim
维数)和一个带有len(indexes) == ndim
的元组indexes
。如果ndlist
是 N-D 数组,我可以执行以下操作:
ndlist[indexes] = (some object)
列表的等效项是什么?请注意,ndim
是任意的,所以我不能像这样硬编码:
ndlist[indexes[0]][indexes[1]]... = (some object)
下面是ndim == 3的示例:
ndlist = [[[10, 10], [10, 10]],[[10, 10],[10,10]]] % 所有元素等于 10 的三维 (2x2x2) 列表
当我事先知道ndim时,我可以像这样编辑 ndlist 的 (0,0,0) 元素:
ndlist[0][0][0] =11%从 10 更改为 11 需要按顺序排列 3 个 [0]
现在假设 ndims == 4(4 维列表)。编辑 ndlist 的 (0,0,0,0) 元素需要这样的东西:
ndlist[0][0][0][0] =11%更改为 11 需要按顺序排列 4 个 [0]
对于任意 ndim:
ndlist[0][0][0]...[0] =11%更改为 11 需要按顺序执行 NDIM [0]
如您所见,对于事先不知道 ndim 的一般情况,我无法以这种方式索引列表,因为它需要键入与 ndim 一样多的 [0]。
如果我有一个这样的数组,而不是列表:
ndarray = np.array(ndlist)
访问 (0, 0, 0, ...,0) 不会有问题,因为我可以使用元组同时索引所有维度,如下所示:
% 3D 案例
索引 = (0,0,0)
ndarray[indexes]
% 4D 案例
索引 = (0,0,0,0)
ndarray[indexes]
% n-d 案例
索引 = (0, 0, 0, ... ,0) % 我可以用代码生成这个
ndarray[索引] = 11
有没有办法用这样的单个元组索引列表?更好的是,元组可以保存切片而不是索引吗?对于实例数组还允许这样做:
ndarray[0:2, 0, 0] = np.array([0, 0])
发现我的问题的唯一解决方案是使用递归一次索引一个维度。有没有更好的解决方案?谢谢!
现在我明白了这个问题。如果您愿意有一个功能为您执行此操作,那将很容易。否则,您需要创建自己的列表类型。
功能
您将需要一个函数来获取列表并n
(未知)数量的元素。n
意味着您将需要*argv
该函数将获取列表并获取n
(argv
)中的第i
个元素。
def get_element(the_list, *argv):
sub_list = the_list.copy()
for i in argv:
sub_list = sub_list[i]
return sub_list
注意:该函数会复制原始list
以确保其未更改。
注意:您还需要处理index out of range
错误。现在它会引发一个错误TypeError: 'blabla' object is not subscriptable
.
您自己的列表类型
在这里,您将创建一个具有任何名称的类(让我们坐TypedList
),该类继承自list
并覆盖__getitem__
方法。
class TypedList(list):
def __getitem__(self, keys):
sub_list = self.copy()
for i in keys:
sub_list = sub_list[i]
return sub_list
if __name__ == '__main__':
ndlist = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
lst = TypedList(ndlist)
print(lst[1, 1, 0])
在这里,您还需要处理index out of range
错误。
评论后编辑。
你说得很对,我实际上没有回答这个问题。既然你已经接受了我的回答,我就想办法去做。
一些编辑
我的实现有一个小(实际上是巨大的)问题。如果仅使用整数作为索引,它将失败。因此,代码必须更改为:
class TypedList(list):
def __getitem__(self, keys):
sub_list = self.copy()
if isinstance(keys, int):
return sub_list[keys]
for i in keys:
sub_list = sub_list[i]
return sub_list
现在。我必须澄清
Python 永远不会复制你在函数调用期间传递的对象。
那是什么意思?如果将传递的对象修改为函数,则对象本身将更改。请注意,我是如何先复制列表,然后再处理列表的。请参阅:https://stackoverflow.com/a/575337/2681662
我们将通过编写一个实际修改传递对象的函数来利用这一点:
def set_value(the_list, keys, value):
for i in range(len(keys) - 1):
the_list = the_list[keys[i]]
the_list[keys[-1]] = value
现在唯一要做的就是,以某种方式设法使这个函数成为我们类的方法并从__setitem__
使用它
class TypedList(list):
def __set(self, the_list, keys, value):
for i in range(len(keys) - 1):
the_list = the_list[keys[i]]
the_list[keys[-1]] = value
def __setitem__(self, keys, value):
if isinstance(keys, int):
super().__setitem__(keys, value) # <- This has to be done. Otherwise maximum recursion depth would occurre...
else:
self.__set(self, keys, value)
def __getitem__(self, keys):
sub_list = self.copy()
if isinstance(keys, int):
return sub_list[keys]
for i in keys:
sub_list = sub_list[i]
return sub_list
if __name__ == '__main__':
ndlist = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
lst = TypedList(ndlist)
lst[1, 1, 0] = 22
print(lst)
这里我们有一个名为__set
的私有方法,__setitem__
会调用它来修改self
这是一种list
。