Tupel in Liste und zurück konvertieren

205

Ich arbeite derzeit an einem Karteneditor für ein Spiel in Pygame, der Kachelkarten verwendet. Das Level besteht aus Blöcken in der folgenden Struktur (obwohl viel größer):

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

Dabei ist "1" ein Block, der eine Wand ist, und "0" ist ein Block, der leere Luft ist.

Der folgende Code behandelt im Wesentlichen die Änderung des Blocktyps:

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

Da die Ebene jedoch in einem Tupel gespeichert ist, kann ich die Werte der verschiedenen Blöcke nicht ändern. Wie ändere ich auf einfache Weise die verschiedenen Werte in der Ebene?

user2133308
quelle
12
Verwenden Sie kein Tupel, sondern nur eine Liste von Anfang an. Es könnte Ihren Code wirklich verlangsamen, wenn Ihr Level riesig ist, wenn Sie sie weiter konvertieren müssen
Jamylak
4
Wie wäre es mit Listen anstelle von Tupeln von Anfang an?
Krzysztof Bujniewicz
4
@ user2133308 Übrigens nur ein Kompatibilitätshinweis, Sie sollten die Ganzzahldivision verwenden, //anstatt nur, /weil in Python 3 /eine Gleitkommadivision durchgeführt und Ihr Code durcheinander gebracht wird.
Jamylak

Antworten:

283

Tupel in Liste konvertieren:

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

Liste in Tupel konvertieren:

>>> l = ['my', 'name', 'is', 'mr', 'list']
>>> l
['my', 'name', 'is', 'mr', 'list']
>>> tuple(l)
('my', 'name', 'is', 'mr', 'list')
Khonix
quelle
5
Das funktioniert bei mir nicht. Wenn ich den Code im ersten Block ausführe, um das Tupel t in eine Liste zu konvertieren, indem ich t an list () übergebe, erhalte ich die Fehlermeldung: "*** Fehler im Argument: '(t)'" Dies scheint zu passieren ich nur beim Debuggen. Immer noch verwirrt.
Jimmy
4
@ Jimmy, weil list ein Debugger-Befehl ist, p list(...)stattdessen ausführen .
Moritz
73

Sie haben ein Tupel von Tupeln.
So konvertieren Sie jedes Tupel in eine Liste:

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

--- ODER ---

map(list, level)

Und nachdem Sie mit der Bearbeitung fertig sind, konvertieren Sie sie einfach zurück:

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

--- ODER --- (Danke @jamylak)

tuple(itertools.imap(tuple, edited))

Sie können auch ein Numpy-Array verwenden:

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

Zum Manipulieren:

if clicked[0] == 1:
    x = (mousey + cameraY) // 60 # For readability
    y = (mousex + cameraX) // 60 # For readability
    a[x][y] = 1
pradyunsg
quelle
2
NumPy ist das grundlegende Paket für wissenschaftliches Rechnen mit Python. Das Hauptobjekt von NumPy ist das homogene mehrdimensionale Array. Es ist eine Tabelle von Elementen (normalerweise Zahlen) vom gleichen Typ, die durch ein Tupel positiver Ganzzahlen indiziert sind.
Pradyunsg
23

Sie können eine Liste von Listen haben. Konvertieren Sie Ihr Tupel von Tupeln in eine Liste von Listen mit:

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

oder

level1 = map(list, level1)

und ändern Sie sie entsprechend.

Aber ein numpy Array ist cooler.

Eumiro
quelle
18

Tupel in Liste konvertieren

(In der angegebenen Frage fehlten Kommas zwischen den Tupeln. Sie wurden hinzugefügt, um eine Fehlermeldung zu vermeiden.)

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

Methode 2:

level1 = map(list,level1)

print(list(level1))

Methode 1 dauerte --- 0,0019991397857666016 Sekunden ---

Methode 2 dauerte --- 0,0010001659393310547 Sekunden ---

Aravind Krishnakumar
quelle
14

Warum versuchen Sie nicht, seinen Typ von einem Tupel in eine Liste zu konvertieren und umgekehrt?

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)
TheRedstoneLemon
quelle
5

Beide Antworten sind gut, aber ein kleiner Rat:

Tupel sind unveränderlich, was bedeutet, dass sie nicht geändert werden können. Wenn Sie also Daten bearbeiten müssen, ist es besser, Daten in einer Liste zu speichern, um unnötigen Overhead zu reduzieren.

In Ihrem Fall extrahieren Sie die Daten in eine Liste, wie von eumiro gezeigt, und erstellen Sie nach dem Ändern ein ähnliches Tupel mit ähnlicher Struktur wie die Antwort von Schoolboy.

Auch wie vorgeschlagen ist die Verwendung von Numpy Array eine bessere Option

Tanzil
quelle
Sie sollten auch in diese Antwort schreiben, numpydie die schnellste Lösung für die Arbeit mit dieser Art von Daten bietet.
Jamylak
Natürlich können Sie unveränderliche Datenstrukturen wie Tupel verwenden, auch wenn Sie Daten bearbeiten. Die ganze Prämisse der funktionalen Programmierung und all das, was weitgehend auf der Persistenz von Daten aufbaut. Aber natürlich möchten Sie in Python Land vielleicht mit den Massen gehen und frei mutieren ...
nperson325681
4

Die Liste zu Tupel und zurück kann wie folgt erfolgen

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)
Vijay Rangarajan
quelle
2

Sie könnten Ihre Inhalte erheblich beschleunigen, wenn Sie nur eine Liste anstelle einer Liste von Listen verwenden. Dies ist natürlich nur möglich, wenn alle Ihre inneren Listen dieselbe Größe haben (was in Ihrem Beispiel zutrifft, also nehme ich dies einfach an).

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)

Und Sie könnten noch schneller sein, wenn Sie ein Bitfeld anstelle einer Liste verwenden:

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)

mit

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

Aber das funktioniert nur, wenn Ihre Felder natürlich nur 0 oder 1 enthalten. Wenn Sie mehr Werte benötigen, müssen Sie mehrere Bits kombinieren, was das Problem erheblich komplizierter machen würde.

Alfe
quelle