Koordinaten einem Array zuordnen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Hallo zusammen,
wenn ich, ich nenne sie mal Koordinaten als Tupel in einer Liste ablege also [ (1,1), (1,3), (2,3) ..... ] und ich ein 2D Array erstellt habe, und dieses mit beispielsweise nullen gefüllt habe. Wie schaffe ich es bloß, das ich dann von den Koordinaten ausgehend, die betreffende 0 in dem Array dann auf 1 ändere?

Also hätte ich wie oben genannt die beiden Koordinaten sollte das dann so sein (bei einer vorher festgelegten Größe des Array/MAtrix:

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

Was wäre da eine einfache Lösung?!
BlackJack

@duodiscus: Naja, man muss halt wie immer schauen was man hat, und dann was man braucht, und dann überlegen welche Schritte dort hin führen können. Du hast eine Liste mit Tupeln mit Koordinaten. Wobei die Werte jeweils um eins zu hoch sind, weil im Rechner üblicherweise bei 0 angefangen wird zu zählen, also die Koordinate ganz oben links (0, 0) und nicht (1, 1) ist. Da die Anpassung auf alle Werte gleich angewendet werden muss, bietet es sich an die Koordinaten erst einmal in ein zweidimensionales Array zu wandeln, weil man dann ganz leicht 1 von allen Werten abziehen kann. Arrays kann man nicht mit Koordinaten indexieren, aber mit einem Tupel von Arrays mit Indexwerten pro Dimension, also technisch gesehen das vorhandene Koordinatenarray transponiert und in ein Tupel umgwandelt. Das geht auch ganz einfach. Kommt also das hier bei heraus, in Einzelschritten:

Code: Alles auswählen

In [88]: import numpy as np

In [89]: A = np.zeros((3, 7), dtype=int)

In [90]: A
Out[90]: 
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])

In [91]: cs = [(1, 1), (1, 3), (2, 3)]

In [92]: np.array(cs)
Out[92]: 
array([[1, 1],
       [1, 3],
       [2, 3]])

In [93]: np.array(cs) - 1
Out[93]: 
array([[0, 0],
       [0, 2],
       [1, 2]])

In [94]: (np.array(cs) - 1).T
Out[94]: 
array([[0, 0, 1],
       [0, 2, 2]])

In [95]: tuple((np.array(cs) - 1).T)
Out[95]: (array([0, 0, 1]), array([0, 2, 2]))

In [96]: A[tuple((np.array(cs) - 1).T)]
Out[96]: array([0, 0, 0])

In [97]: A[tuple((np.array(cs) - 1).T)] = 1

In [98]: A
Out[98]: 
array([[1, 0, 1, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Danke für dein Beispiel. Bisher habe ich die numpy Funktion noch nicht kennengelernt, bzw. ich weiß nicht was man damit genau anfangen kann. Ich werde es mal nachlesen im Tutorial. Da ich das als Thema aber noch nicht habe, denke ich das ich das möglichst ohne diese Funktion lösen soll.

Ich habe zum Beispiel mein Array schon gebaut, allerdings ohne Numpy:

Code: Alles auswählen

def Array2D(a, b, init):
    array = [ ]
    for x in range(0,a):
        array.append([])
        for y in range(0,b):
            array[x].append(init)
    return array
Ich versuche mal deine Lösung nachzuvollziehen ;-)
BlackJack

@duodiscus: Du bringst hier den Begriff Array mit Liste durcheinander. Mit Arrays sind in Python eigentlich so gut wie immer Numpy-Arrays gemeint. Was Du hier hast sind Listen, also der Datentyp `list`.

Und es ist ziemlich ausführlich geschrieben und auch ein wenig zu kompliziert. Statt eine leere Liste an `array` anzuhängen um dann da in jedem Durchlauf der inneren Schleife erst wieder über einen Index dran zu kommen um ein Element anzuhängen, würde man eher mit der inneren Schleife eine Liste erstellen und die dann am Ende der äusseren Schleife an das Ergebnis anhängen. Dann braucht man den Laufvariablen auch keine richtigen Namen geben, sondern kann den konventionellen `_` für Werte die nicht benutzt werden, verwenden und stattdessen `a` und `b` aussagekräftigere Namen verpassen:

Code: Alles auswählen

def create_2d_list(width, height, init_value):
    result = list()
    for _ in range(height):
        row = list()
        for _ in range(width):
            row.append(init_value)
        result.append(row)
    return result
Die innere Schleife lässt sich kürzer und effizienter als eine Multiplikation einer Liste mit einer Zahl ausdrücken, damit wird man dann auch den Namen für die Zeilenliste los:

Code: Alles auswählen

def create_2d_list(width, height, init_value):
    result = list()
    for _ in range(height):
        result.append([init_value] * width)
    return result
Und nun besteht der Wert der angehängt wird, nur noch aus einem einzigen Ausdruck, also kann man das kürzer und einfacher als „list comprehension” ausdrücken und auch noch den Namen für das Ergebnis einsparen:

Code: Alles auswählen

def create_2d_list(width, height, init_value):
    return [[init_value] * width for _ in range(height)]
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Okay, danke für die Zusammenfassung der Erstellung von 2D Listen. Habe jetzt mein Programm den Beispielen folgend angepasst (ohne Numpy). Jetzt wäre meine Frage dahingehend noch gestellt, wie ich die Lösung ohne Numpy Funktion hinbekomme, das aus der 0 eine 1 in der 2D Liste wird, sobald man die Koordinaten von der entsprechenden 0 eingegeben hat. Da komme ich nicht weiter, und denke das ich es ohne weitere Hilfe auch net so mehr hinbekomme. :K
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast eine Liste mit Listen. Wie Du mit Index auf ein Listenelement zugreifst weißt Du? Dann weißt Du auch, wie Du auf Listenelemente zugreifst, die in Listen stecken, die Du erst mit einem Indexzugriff aus einer anderen Liste herausholen mußt.
BlackJack

@duodiscus: Beschreibe doch mal in Worten wie Du vorgehen müsstest. Du hast eine Liste mit Listen, nennen wir sie mal `data` und Koordinaten, sagen wir mal x=0 und y=2, wobei wir der Einfachheit mal annehmen das die schon von 0 an gezählt sind, und man nicht mehr 1 abziehen muss.

Code: Alles auswählen

In [1]: data = [[0] * 7 for _ in range(5)]

In [2]: data
Out[2]: 
[[0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]]

In [3]: x, y = 0, 2
Lassen wir das verändern erst mal aussen vor: Was müsstest Du machen um die 0 an der Stelle (0, 2) auszulesen? Und wenn Du das machen kannst, ist es nur ein kleiner Schritt da auch einen anderen Wert zu hinterlegen.
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Danke für Eure Hilfen!
Also wenn ich auf diese Koordinate wie in deinem Beispiel zugreifen möchte, würde ich das folgendermaßen machen:

Code: Alles auswählen

data = [[0] * 7 for _ in range(5)]
>>> data
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]

xy = data[0][2]
xy
0

Ich kriege es nur nicht getrommelt, diesen Ablauf sozusagen automatisiert auf die Beine zu stellen.

Eigentlich ja 1 statt 2, da ja von 0 an indexiert wird....
BlackJack

@duodiscus: Was meinst Du mit „automatisiert”? Wenn Du jetzt nicht 0 und 2 fest als Zahlen hast sondern die als Variablen `x` und `y`, dann weisst Du nicht mehr wie das geht‽
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Jo, habe es hinbekommen. Eine Frage habe ich allerdings noch, wie kann ich die Ausgabe so hinkriegen das die 2D Liste schön formatiert ausgegeben wird?

Also statt:

Code: Alles auswählen

[[1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]
jeweils eine Zeile je Liste?
BlackJack

@duodiscus: Du könntest eine Funktion schreiben die in einer Schleife die Listen nacheinander ausgibt.
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Hmm, okay, wenn ich aber eine neue Funktion mache, dann gibt er gar nichts aus. Nur wenn ich es in die Funktion selbst lege. Aber ich fände es besser wenn es eine eigene Funktion wäre, die die Liste aufruft. Aber das funktioniert scheinbar net.
BlackJack

@duodiscus: Ich verstehe das Problem gerade nicht. Wenn Du eine Funktion schreibst in der etwas ausgegeben wird, dann wird auch etwas ausgegeben. Sonst hast Du etwas falsch gemacht.

Und ich meine natürlich eine eigene Funktion. Wie sähe denn eine „nicht-eigene” Funktion aus?

Die Liste ruft keine Funktionen auf. Das ist eine komische Formulierung.
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Habe es nun fertig ;) danke tzd für Hilfen!
Die Liste war in der Funktion und net Modul global
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

duodiscus hat geschrieben:Die Liste war in der Funktion und net Modul global
Dann solltest du das wieder ändern. Globale Variablen sind keine gute Idee, diese schaffen zusätzlichen Zustand, welcher sich auch noch quer über das gesamte Programm verteilt. Das möchte man nicht warten, daher lässt man es gleich bleiben. Wenn eine Funktion ein Objekt verarbeiten soll, dann über gibst du das Objekt der Funktion als Parameter. Das Ergebnis eines Funktionsaufrufs gibst du als Rückgabewert aus der Funktion zurück. Auf keinen Fall solte eine Funktion Objekte verändern, die nicht als Parameter hineingekommen sind.
Das Leben ist wie ein Tennisball.
Antworten