Конвертировать кортеж в список и обратно


207

В настоящее время я работаю над редактором карт для игры в 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

Но так как уровень хранится в кортеже, я не могу изменить значения разных блоков. Как мне легко изменить различные значения уровня?


12
не используйте кортеж, просто используйте список с самого начала. Это может действительно замедлить ваш код, если ваш уровень огромен, если вы должны продолжать конвертировать их
jamylak

4
как насчет того, чтобы с самого начала использовать списки вместо кортежей?
Кшиштоф Буйневич

4
@ user2133308 Кстати, только о совместимости, вы должны использовать целочисленное деление, //а не только /потому, что в Python 3 /будет выполнять деление с плавающей запятой и испортить ваш код.
jamylak

Ответы:


285

Преобразовать кортеж в список:

>>> 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')

6
Это не работает для меня. Если я запускаю код в первом блоке для преобразования кортежа t в список, передавая t в list (), я получаю сообщение об ошибке: "*** Ошибка в аргументе: '(t)'" меня только во время отладки. Все еще в замешательстве.
Джимми

5
@Jimmy, потому что list - это команда отладчика, p list(...)вместо этого запустите .
Мориц

74

У вас есть кортеж кортежей.
Чтобы преобразовать каждый кортеж в список:

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

--- ИЛИ ---

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

24

Вы можете иметь список списков. Преобразуйте ваш кортеж в список списков, используя:

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

или

level1 = map(list, level1)

и измените их соответственно.

Но клочковатый массив круче.


18

Чтобы преобразовать кортежи в список

(Между кортежами в данном вопросе отсутствовали запятые, они были добавлены для предотвращения сообщения об ошибке)

Способ 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)

Способ 2:

level1 = map(list,level1)

print(list(level1))

Способ 1 занял --- 0.0019991397857666016 секунд ---

Способ 2 занял --- 0.0010001659393310547 секунд ---


14

Почему бы вам не попробовать преобразовать его тип из кортежа в список и наоборот.

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 вы можете пойти с массами и свободно мутировать ...
nperson325681

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

Вы могли бы значительно ускорить ваши вещи, если бы вы использовали только один список вместо списка списков. Это возможно, конечно, только если все ваши внутренние списки имеют одинаковый размер (что верно в вашем примере, поэтому я просто предполагаю это).

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, конечно. Если вам нужно больше значений, вам придется объединить несколько битов, что значительно усложнит задачу.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.