使用变量元组访问列表元素
免责声明:我是个初学者,自学Python的用户。
ndarrays(即N维数组)有个很酷的功能,就是可以用一个整数的元组来作为索引(比如 myNDArray[(1,2)] == myNDArray[1][2]
)。这意味着我可以把索引当成一个变量(比如叫它 indicesTuple),等到脚本决定要处理ndarray的哪个部分时,再把这个变量指定为一个整数的元组,然后用它来访问ndarray的一部分(比如 myNDArray[indicesTuple]
)。使用变量的好处在于,元组的长度可以根据ndarray的维度来变化。
不过,这样做让我只能处理数值类型的数组。我试过用列表,但列表不能用元组作为索引(比如 myList[(1,2)]
会报错)。有没有办法像处理函数参数那样“解包”元组来用作列表的索引?或者有没有更简单或更有效的方法?
更新:哇,我居然忘了这个功能。基本上,我后来学到可以在初始化ndarray时加上参数 dtype=object,这样就可以让ndarray包含多种类型的Python对象,跟列表差不多。至于访问列表,正如一位评论者提到的,我可以用for循环遍历变量 indicesTuple,逐层访问列表中更深的元素。关于就地编辑的部分,可以参考被接受的评论,真的是很用心。
4 个回答
Python没有多维列表,所以像myList[(1,2)]
这样的写法只能算是一种快捷方式,实际上它等同于(myList[1], myList[2])
(虽然有时候这样用挺方便的,不过你也可以用import operator; x = operator.itemgetter(1,2)(myList)
来实现同样的效果)。
如果你的myList
长得像下面这样:
myList = [ ["foo", "bar", "baz"], ["a", "b", c" ] ]
那么myList[(1,2)]
就不管用(也不太合理),因为myList
并不是一个二维列表:它是一个包含其他列表引用的列表。你需要用myList[1][2]
,因为第一个索引myList[1]
会返回["a", "b", "c"]
这个列表的引用,然后你再用第二个索引[2]
来获取"c"
这个值。
稍微相关的是,你可以用字典来模拟稀疏数组,具体做法是用元组作为键,搭配默认字典来实现。
import collections
d = collections.defaultdict(str)
d[(1,2)] = "foo"
d[(4,5)] = "bar"
你尝试用的任何其他元组作为键都会返回空字符串。这并不是一个完美的模拟,因为你不能像访问数组的完整行或列那样直接访问,而是需要使用类似于
row1 = [d[1, x] for x in range(C)] # where C is the number of columns
col3 = [d[x, 3] for x in range(R)] # where R is the number of columns
使用元组作为索引的字典
>>> width, height = 7, 6
>>> grid = dict(
((x,y),"x={} y={}".format(x,y))
for x in range(width)
for y in range(height))
>>> print grid[3,1]
x=3 y=1
使用列表的列表
>>> width, height = 7, 6
>>> grid = [
["x={} y={}".format(x,y) for x in range(width)]
for y in range(width)]
>>> print grid[1][3]
x=3 y=1
在这种情况下,你可以创建一个获取和设置的函数:
def get_grid(grid, index):
x, y = index
return grid[y][x]
def set_grid(grid, index, value):
x, y = index
grid[y][x] = value
你还可以更进一步,创建一个自己的类,这个类里面包含一个列表的列表,并定义一个索引器,可以用元组作为索引来进行相同的操作。这样做可以进行更合理的边界检查,并且比字典提供更好的诊断信息,不过这需要一些设置。我觉得字典的方法对于快速探索来说是不错的选择。
假设你有一组 (i,j)
的索引列表
indexList = [(1,1), (0,1), (1,2)]
还有一个你想要从中获取数据的二维列表
l = [[1,2,3],
[4,5,6],
[7,8,9]]
你可以用一种叫做列表推导的方法来获取这些元素,具体如下
>>> [l[i][j] for i,j in indexList]
[5, 2, 6]
这样你的索引可以是你想要的任何值。在列表推导中,这些索引会被拆开,并用作列表的索引。对于你具体的应用,我们需要看看你的索引变量是从哪里来的,但大致上就是这个意思。
我理解你的问题是:
我有一个N维的列表,还有一个包含N个值的元组(T1, T2... TN)。我该如何用这个元组的值来访问这个列表呢?我不知道N的值会是什么。
我不知道有没有现成的方法可以做到这一点,但你可以写一个方法,逐层深入列表,直到找到最里面的值。
def get(seq, indices):
for index in indices:
seq = seq[index]
return seq
seq = [
[
["a","b"],
["c","d"]
],
[
["e","f"],
["g","h"]
]
]
indices = [0,1,0]
print get(seq, indices)
结果:
c
你也可以用一行代码来实现这个功能,使用reduce
,不过这样可能会让读代码的人不太明白你想要做什么。
print reduce(lambda s, idx: s[idx], indices, seq)
(如果你用的是3.X版本,你需要从functools
导入reduce
,所以实际上是两行代码。)
如果你想在这个N维列表中设置值,可以用get
来访问列表的第二层,然后把值赋给它。
def set(seq, indices, value):
innermost_list = get(seq, indices[:-1])
innermost_list[indices[-1]] = value