我知道元组是不可变的结构,所以如果我有一个元组列表。
list1 = [(1,2,3,4),(2,3,4,5)]
我必须更改元组的第一个元素,然后我将不得不基本上写:
list1[0] = (2,2,3,4) not list1[0][0] = 2 because tuple is immutable
对于每个元素,我都需要这样做。这是一个有效的操作,还是如果需要定期执行此操作,最好使用列表列表?
如果需要修改列表的元素,请使用可变元素。将不可变对象存储在可变容器中不会使对象可变。
至于效率,构造一个新的元组比修改列表更昂贵。但对于大多数操作,可读性比运行时性能更重要,因此请先优化可读性。另请记住,当从外部引用列表列表的元素时,您可能会得到副作用:
l1 = [1, 2, 3]
l2 = ['a', 'b', 'c']
lol = [l1, l2]
lol[0][0] = 0
print(l1) # prints [0, 2, 3]
更新:为了支持我对效率的主张,以下是使用IPython %timeit
魔法的一些时间:
>>> list_of_lists = [[1,2,3,4] for _ in xrange(10000)]
>>> list_of_tuples = map(tuple, list_of_lists)
>>> def modify_lol():
... for x in list_of_lists:
... x[0] = 0
...
>>> def modify_lot():
... for i, x in enumerate(list_of_tuples):
... list_of_tuples[i] = (0,) + x[1:]
...
>>> %timeit modify_lol()
100 loops, best of 3: 6.56 ms per loop
>>> %timeit modify_lot()
100 loops, best of 3: 17 ms per loop
因此,对于此任务,列表列表的速度提高了 2.6×。
好吧,看看直接解决方案,你得到的等价物
list[0] = (2,) + list[0] [1:]
这应该足以让您以编程方式执行此操作。它仍在制作副本,但这相当快,就像切片元组一样。
如果你这样定义你的变量:
list1 = [[1,2,3,4],[2,3,4,5]]
您将能够像这样更改列表元素的值:
list1[0][0] = 2
现在您的变量值将是:
list1 = [[2,2,3,4],[2,3,4,5]]
当您只需要更改特定元素时,效率就会降低。例如,假设您有两个元组。
tup1 = (1, 2, 3, 4)
tup2 = (5, 6, 7, 8)
你想把两个元组的第一个元素都改成 9。
tup1 = (9, 2, 3, 4)
tup2 = (9, 6, 7, 8)
是唯一的方法,如果你有一百万个具有不同值的元组,都需要从 9 开始,那么这种方式显然是无效的,你将不得不键入并重新分配所有元组不同的值。
相反,您应该使用列表。
l1 = [1, 2, 3, 4]
l2 = [5, 6, 7, 8]
然后你可以做
list = [l1, l2]
for l in list:
l[0] = 9
这会将所有第一个元素更改为 9,而无需硬编码一百万个列表。
l1
现在[9, 2, 3, 4]
l2
现在[9, 6, 7, 8]
您有两个选择:
L = [(1,2,3,4),(2,3,4,5)]
L = [tuple([2]+subL[1:]) for subL in L]
这很慢,因为它必须重新创建所有这些元组。
或
L = [(1,2,3,4),(2,3,4,5)]
L = [list(i) for i in L] # or L = map(list, L)
for subL in L:
subL[0] = 2
如果你知道你的列表项中只有四个元素,但它们必须是可变的,那么最好的选择(在我看来(是使用一个类:
class WXYZ: # example name, give yours something more sensible to the nature of the code
def __init__(self, w=0, x=0, y=0, z=0)
self.w = w
self.x = x
self.y = y
self.z = z
然后,您的代码将如下所示:
list1 = [WXYZ(1,2,3,4), WXYZ(2,3,4,5)]
list1[0].w = 2
如果需要在for
循环中使用它,也可以轻松添加__iter__
方法:
def __iter__(self):
return iter((w,x,y,z))
或者,如果你想变得聪明,你可以做
def __iter__(self):
yield w
yield x
yield y
yield z
如果你真的担心内存使用(在这种情况下为什么要使用python?(,你可以定义__slots__ = ("w","x","y","z")
来分配所需的内存。