durch unbekannte mehrdimensionale arrays slicen

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.
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

durch unbekannte mehrdimensionale arrays slicen

Beitragvon murph » Mittwoch 13. September 2006, 21:35

hi!
ich muss durch arrays slicen, deren dimensionalität ich nicht kenne.
das befüllen war nicht das problem, da konnte ich mich mit for-schleifen drumrummogeln, nur halte ich es nicht für sinnvoll,
nun mit zig if's zu kommen, sondern möchte eine schönere lösung.
meine koordinaten sind in einem tuple ungefähr so (2, 3, 5),
der array sieht so aus:
[[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0]
]
nun soll an der stelle die null in einen anderen wert umgewandelt werden.
bis jetzt habe ich numeric benutzt, einfach, weil ich anspruchslos bin, erstelle damit sowieso nur diesen array und will dann durch diesen slicen.
ich hätte auch scipy genommen, dachte, dass wäre der nachfolger, konnte darin aber keine funktion erkennen, die so etwas gebracht hätte, von einer doku darüber ganz zu schweigen.
wie kann ich nun das ganze anstellen, es könnten auch 6 dimensionen sein...
BlackJack

Beitragvon BlackJack » Mittwoch 13. September 2006, 23:35

Irgendwie kann ich mit Deiner Beschreibung nichts anfangen. Du hast ein Tupel mit drei Werten und ein Array mit zwei Dimensionen, und nun?

Ich weiss auch nicht so recht was Du unter "slicen" verstehst. In Python verbinde ich damit die Slice-Syntax um ein Stück aus einer Liste zu extrahieren, also `lst[10:20:2]` um jedes zweite Element zwischen Index 10 und 20 auszulesen, bzw. das gleiche mit eventuell mehr Dimensionen bei `numarray`/`numpy` Arrays. Bei denen allerdings keine Kopie sondern nur eine neue "Sicht" auf einen Ausschnitt des Arrays zurückgegeben wird.
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

Beitragvon murph » Donnerstag 14. September 2006, 08:18

das problem ist, dass ich vorher nicht weiß, wieviele dimensionen der array hat. nun muss ich die stelle ansteuern, die ich über einen tuple bekomme, sprich zb: 2, 3, 6. das wären angaben für einen 3-dimensionalen array.
aber es könnte auch 3, 2, 9, 6 sein oder noch mehr stellen haben.
nun will ich an der stelle, deren koordinaten ich habe, den wert verändern.
also habe ich mir vorgestellt, dass das so aussieht:

Code: Alles auswählen

coordinates = (12, 36, 12)
a, b, c = coordinates
my_array[a, b, c] = 3


nun funktioniert das ja nur, wenn man weiß, dass die koordinaten drei dimensionen umfassen. nun möchte ich, dass im falle, das es 4 dimensionen sind, "automatisch" folgendes steht

__edit__(war ein fehler drin)

Code: Alles auswählen

coordinates = (12, 36, 12, 36)
a, b, c, d = coordinates
my_array[a, b, c, d] = 3


nun könnte ich fragen, wie lang der tuple ist und danach dann den wert im array setzen, nur finde ich das extrem unschön und wollte daher eine alllgemeinere lösung, bei der ihc mich nicht darum kümmern muss, wieviele dimensionen nun mein array hat.

//edit:
hab jetzt auf numarray gewechselt, da das weitausmehr möglichkeiten bietet.
nun brauche ich nur noch etwa folgendes:

Code: Alles auswählen

self.matrix.__setitem__(*[current_place], ship_id)

das geht leider nicht, da die syntax verlangt, dass die liste als letztes stehen muss, das aber nun mal nicht mit der reihenfolge von __setitem__ zusammenpasst.
Zuletzt geändert von murph am Freitag 15. September 2006, 19:00, insgesamt 1-mal geändert.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Beitragvon CM » Donnerstag 14. September 2006, 10:15

Hoi murph,

Du hast Numeric? Dann kannst Du die Dimensionalität ganz einfach so ermitteln:

Code: Alles auswählen

from Numeric import *
a = array([[ 0, 1, 2, 3],
               [10,11,12,13]])
s = a.shape

Dann ist s ein tuple mit (2,4) zum Inhalt.

Scipy ist NICHT der Nachfolger von Numeric und war es nie. Dies ist numpy. Die Syntax für numpy ist identisch. Auf der Scipy Seite gibt es genügend Dokumentation, sowohl für numpy als auch für scipy.

Slicing funktioniert für Numeric und numpy arrays eigentlich genauso wie für mehrdimensionale Listen.

Dein Problem würde ich abstrahieren und in eine eigene Funktion packen oder gar noch weiter enkapsulieren. Ich habe zwar oft arrays verschiedener Dimensionalität, versuche aber diese niemals zu mischen, was einfach ist, weil diese arrays meist auch logisch anderen Dingen entsprichen.

Gruß,
Christian
Benutzeravatar
akis.kapo
User
Beiträge: 127
Registriert: Freitag 1. September 2006, 12:58

Beitragvon akis.kapo » Donnerstag 14. September 2006, 10:39

unabhängig von numpy, numarray und anderen modulen kannste ganz allgemein
durch vollgende methode die dimensionalität bestimmen.


Code: Alles auswählen

array_to_examine = <dein_array>
dimensions = 0
try:
    while True:
        if len(array_to_examine) > 0:
            dimensions += 1
            array_to_examine = array_to_examine[0]
except TypeError:
    print dimensions


EDIT:
zugegeben: das mit dem try,except ist mal _brutal_ hässlich... :?
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Beitragvon CM » Donnerstag 14. September 2006, 11:20

Stimmt: Ineffizient, unschön und nicht funktional. Du weißt so zwar wie viele Dimensionen es gibt, aber nicht wie lang eine Achse ist. .shape liefert beide Werte auf einmal.

Gruß,
Christian
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

Beitragvon cime » Donnerstag 14. September 2006, 11:49

wenn ich ihn verstanden habe, muss er die anzahl der dimensionen doch gar nicht wissen, sondern nur innerhalb dieses n-dimensionalem arrays einen wert an einer bestimmten stelle ändern ... würde ich einfach rekursiv machen ...

Code: Alles auswählen

a= <dein array>

def ersetze_rekursiv(array,tuple,wert):
    if len(tuple)==1:
        array[tuple[0]]=wert
    else:
        ersetze_rekursiv(array[tuple[0]],tuple[1:],wert)

ersetze_rekursiv(a,<deine Positionsangaben>,<neuer wert an der Position>)


ungetestet ... müsste aber (zumindest unter Python 2.3) funktionieren

PS: da ich jetzt nicht weiß, mit welchen speziellen arrays du handhabst, hab ich es einfach mal wie eine liste gehandhabt ... vielleicht müsstest du also den wert noch anders zuweisen (bei tupels würde es ja so nicht gehen).
BlackJack

Beitragvon BlackJack » Donnerstag 14. September 2006, 12:58

murph hat geschrieben:das problem ist, dass ich vorher nicht weiß, wieviele dimensionen der array hat. nun muss ich die stelle ansteuern, die ich über einen tuple bekomme, sprich zb: 2, 3, 6. das wären angaben für einen 3-dimensionalen array.
aber es könnte auch 3, 2, 9, 6 sein oder noch mehr stellen haben.
nun will ich an der stelle, deren koordinaten ich habe, den wert verändern.


Passen denn die Tupel von der Länge her immer mit der Dimension des Arrays zusammen? Das wird aus Deiner Beschreibung nicht so ganz klar.

also habe ich mir vorgestellt, dass das so aussieht:

Code: Alles auswählen

coordinates = (12, 36, 12)
a, b, c = coordinates
my_array[a, b, c] = 3


Das kann man so "kompliziert" machen, man kann sich `a`, `b` und `c` natürlich auch sparen und direkt `coordinates` verwenden.

nun funktioniert das ja nur, wenn man weiß, dass die koordinaten drei dimensionen umfassen. nun möchte ich, dass im falle, das es 4 dimensionen sind, "automatisch" folgendes steht

Code: Alles auswählen

coordinates = (12, 36, 12)
a, b, c, d = coordinates
my_array[a, b, c, d] = 3


Das gibt eine Ausnahme beim entpacken des Tupels -- Du kannst nicht drei Werte an vier Namen binden.

//edit:
hab jetzt auf numarray gewechselt, da das weitausmehr möglichkeiten bietet.
nun brauche ich nur noch etwa folgendes:

Code: Alles auswählen

self.matrix.__setitem__(*[current_place], ship_id)

das geht leider nicht, da die syntax verlangt, dass die liste als letztes stehen muss, das aber nun mal nicht mit der reihenfolge von __setitem__ zusammenpasst.


Selbst wenn die Syntax das erlauben würde: Die Methode erwartet nur zwei Argumente und nicht beliebig viele. Ausserdem ruft man `__setitem__()` nicht direkt auf sondern über die `[]` Syntax, dafür ist sie ja da.

Also nochmal am Beispiel: Wenn die Zahl der Elemente im Tupel mit der Anzahl der Dimensionen übereinstimmt, dann brauchst Du nur das Tupel als Index benutzen:

Code: Alles auswählen

In [14]: a = numarray.zeros((3, 5, 5))

In [15]: a
Out[15]:
array([[[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],
        [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],
        [0, 0, 0, 0, 0]]])

In [16]: b = (1, 2, 3)

In [17]: a[b] = 42

In [18]: a
Out[18]:
array([[[ 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],
        [ 0,  0,  0, 42,  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,  0]]])


Falls beide nicht übereinstimmen, dann musst Du nachschauen um wieviel Dimensionen das Array grösser ist als die Anzahl der Elemente im Tupel und das dann zum Beispiel mit 0en erweitern.
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

Beitragvon murph » Freitag 15. September 2006, 19:16

@cime:
thx, das ist die lösung!
@blackjack:
ich habe den zuweisungsfehler behoben
mein problem war, dass ich mit der []-syntax keine *list oder *tuple benutzen konnte.
ich werde mir mal ankucken, wie das problem mit den argumenten intern gelöst wurde, denn in der []-syntax werden ja mehrere argumente übergeben, die mit kommatar voneinander getrennt werden.
//edit:
sehe grade, dass das mit dem tuple als adresse klappt!
das hielt ich einfach für zu abwegig, nun habe ich zwei lösungen, nochmal thx!
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

Beitragvon cime » Sonntag 17. September 2006, 16:22

BlackJack hat geschrieben:

Code: Alles auswählen

In [14]: a = numarray.zeros((3, 5, 5))

In [16]: b = (1, 2, 3)

In [17]: a[b] = 42

In [18]: a
Out[18]:
array([[[ 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],
        [ 0,  0,  0, 42,  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,  0]]])


oh, wusste nicht, dass das geht ... wieder etwas gelernt ...

mfg cime

edit: @murph: von mir wurde übrigens der variablenname tuple nicht gut gewählt, da dieser schon mit der klasse tuple belegt ist (und dann halt innerhalb der funktion überschrieben wird. daher solltest du möglichst einen anderen namen wählen .
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

Beitragvon murph » Sonntag 17. September 2006, 18:38

@cime:
das _tuple ist bei mir schon notorisch^^

Wer ist online?

Mitglieder in diesem Forum: __deets__, Bing [Bot], Sirius3