将元组转换为列表并再次转换为元组

290

我目前正在使用瓦片地图制作基于pygame游戏的地图编辑器。 关卡由块构建而成,结构如下(尽管更大):

level1 = (
         (1,1,1,1,1,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,1,1,1,1,1))

其中,“1”代表墙壁方块,“0”代表空气方块。

以下代码基本上是处理方块类型更改的代码:

clicked = pygame.mouse.get_pressed()
if clicked[0] == 1:
    currLevel[((mousey+cameraY)/60)][((mousex+cameraX)/60)] = 1

但是由于水平存储在元组中,我无法更改不同块的值。我如何以简单的方式更改水平中的不同值?


16
不要使用元组,一开始就使用列表。如果你需要不断转换它们,当级别很大时,它可能会严重拖慢代码的速度。请注意保持原有意思并使语言更简单易懂。 - jamylak
4
一开始就使用列表代替元组怎么样? - Krzysztof Bujniewicz
7
@user2133308 顺便提一下,为了保证代码正确性,请使用整数除法运算符 // 而不是普通的 /,因为在 Python 3 中,/ 将执行浮点数除法,可能会破坏您的代码。 - jamylak
11个回答

379

将元组转换为列表:

>>> t = ('my', 'name', 'is', 'mr', 'tuple')
>>> t
('my', 'name', 'is', 'mr', 'tuple')
>>> list(t)
['my', 'name', 'is', 'mr', 'tuple']

将列表转换为元组:

>>> l = ['my', 'name', 'is', 'mr', 'list']
>>> l
['my', 'name', 'is', 'mr', 'list']
>>> tuple(l)
('my', 'name', 'is', 'mr', 'list')

10
对我来说这个不起作用。如果我运行第一段的代码将元组t传递给list()转换为列表,我会收到一个错误信息:“*** Error in argument: '(t)'”。这似乎只在我调试时发生。仍然很困惑。 - Jimmy
15
@Jimmy那是因为list是一个调试器命令,应该使用p list(...)来运行。 - moritz

89

你有一个包含元组的元组。
要将每个元组转换为列表:

[list(i) for i in level] # list of lists

--- OR ---

map(list, level)

在你完成编辑后,只需将它们转换回去:

tuple(tuple(i) for i in edited) # tuple of tuples

--- 或者 ---(感谢 @jamylak)

tuple(itertools.imap(tuple, edited))

您也可以使用numpy数组:
>>> a = numpy.array(level1)
>>> a
array([[1, 1, 1, 1, 1, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 1, 1, 1, 1, 1]])

对于操作:

if clicked[0] == 1:
    x = (mousey + cameraY) // 60 # For readability
    y = (mousex + cameraX) // 60 # For readability
    a[x][y] = 1

2
NumPy是Python科学计算的基础包。NumPy的主要对象是同质多维数组。它是一个元素表格(通常是数字),所有元素类型相同,由正整数元组索引。 - pradyunsg

27

你可以有一个列表的列表。使用以下方法将元组的元组转换为一个列表的列表:

level1 = [list(row) for row in level1]
或者
level1 = map(list, level1)

并相应地进行修改。

但是一个numpy数组更酷。


24
自Python 3.5起(PEP 448 -- Additional Unpacking Generalizations),可以使用以下字面值语法将元组转换为列表:
>>> t = (1,2,3)
>>> lst = [*t]
>>> lst
[1, 2, 3]
>>> *lst,  # back to tuple
(1, 2, 3)

可以使用列表推导式将元组的元组转换为列表的列表:

>>> level1 = (
...      (1,1,1,1,1,1),
...      (1,0,0,0,0,1),
...      (1,0,0,0,0,1),
...      (1,0,0,0,0,1),
...      (1,0,0,0,0,1),
...      (1,1,1,1,1,1))
>>> level1_list = [[*row] for row in level1]
>>> level1_list
[[1, 1, 1, 1, 1, 1], 
 [1, 0, 0, 0, 0, 1], 
 [1, 0, 0, 0, 0, 1], 
 [1, 0, 0, 0, 0, 1], 
 [1, 0, 0, 0, 0, 1], 
 [1, 1, 1, 1, 1, 1]]
>>> *((*row,) for row in level1_list),
((1, 1, 1, 1, 1, 1), 
 (1, 0, 0, 0, 0, 1), 
 (1, 0, 0, 0, 0, 1), 
 (1, 0, 0, 0, 0, 1), 
 (1, 0, 0, 0, 0, 1), 
 (1, 1, 1, 1, 1, 1))
>>> _ == level1
True

20

将元组转换为列表

(在给定的问题中,元组之间缺少逗号,这是为了防止错误消息而添加的)

方法1:

level1 = (
     (1,1,1,1,1,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,1,1,1,1,1))

level1 = [list(row) for row in level1]

print(level1)

方法二:

level1 = map(list,level1)

print(list(level1))

方法1花费了---0.0019991397857666016秒---

方法2花费了---0.0010001659393310547秒---


16

为什么不尝试将其类型从元组转换为列表,反之亦然。

level1 = (
     (1,1,1,1,1,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,1,1,1,1,1))

print(level1)

level1 = list(level1)

print(level1)

level1 = tuple(level1)

print(level1)

5

两个答案都很好,但是有一个小建议:

元组是不可变的,这意味着它们不能被更改。因此,如果您需要操作数据,最好将数据存储在列表中,这将减少不必要的开销。

在您的情况下,按照eumiro所示将数据提取到列表中,在修改后创建一个类似于Schoolboy给出答案的相似结构的元组。

同时,建议使用numpy数组是更好的选择。


你还应该在回答中写道,“numpy”将提供处理这种类型数据的最快速解决方案。 - jamylak
当然,在处理数据时,您可以使用不可变数据结构,例如元组。函数式编程的整个前提和大部分内容都建立在数据的持久性基础上。但当然,在Python世界中,您可能希望跟随大众自由地进行突变... - mike3996

5
将列表转换为元组,然后再转回来可以按照以下方式进行。
import ast, sys
input_str = sys.stdin.read()
input_tuple = ast.literal_eval(input_str)

l = list(input_tuple)
l.append('Python')
#print(l)
tuple_2 = tuple(l)

# Make sure to name the final tuple 'tuple_2'
print(tuple_2)

2

仅使用命令列表对我来说不起作用。

如果您有一个元组,只需迭代直到您拥有必要的元素,之后将其附加到列表中。如果您到了元素级别,您可以轻松更改它。

输入:

level1 = (
         (1,1,1,1,1,1),
         (1,0,0,0,0,1),
         (1,0,0,0,0,1),
         (1,0,0,0,0,1),
         (1,0,0,0,0,1),
         (1,1,1,1,1,1))

level1_as_list=[]
for i in level1:
    inside_list=[]
    for j in i:
        inside_list.append(j)
    level1_as_list.append(inside_list)

print(level1_as_list)enter code here

输出:

[[1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1]]

2

如果您使用一个列表而不是多个列表,可以大大加快处理速度,当然,这仅在所有内部列表的大小相同时才可能实现(在您的示例中是正确的,因此我只是假设如此)。

WIDTH = 6
level1 = [ 1,1,1,1,1,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,1,1,1,1,1 ]
print level1[x + y*WIDTH]  # print value at (x,y)

如果你使用位域而不是列表,你甚至可以更快:

WIDTH = 8  # better align your width to bytes, eases things later
level1 = 0xFC84848484FC  # bit field representation of the level
print "1" if level1 & mask(x, y) else "0"  # print bit at (x, y)
level1 |= mask(x, y)  # set bit at (x, y)
level1 &= ~mask(x, y)  # clear bit at (x, y)

使用

def mask(x, y):
  return 1 << (WIDTH-x + y*WIDTH)

当然,这只适用于您的字段只包含0或1的情况。如果您需要更多的值,则必须组合几个位,这会使问题变得更加复杂。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接