Slicing mehrdimensionaler Arrays

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
rer
User
Beiträge: 5
Registriert: Samstag 19. Mai 2007, 14:13

Hallo,

Ich beschaeftige mich seit ca. 1 Monat mit python, habe bisher sehr viel in Perl gemacht und muss doch feststellen, das python einige Implementierungs- wenn nicht gar Designfehler hat.
Beispiel mehrdimensionale Arrays:Spaltenweises extrahieren aus Matrix

>>>x=[['a0','a1'],['b0','b1']]
>>> x[:][1]
['b0', 'b1']
:shock:
Das ist doch wohl ein schlechter Witz! Ich wuerde da a1,b1 erwarten, und das auch vor dem Hintergrund wo sich python doch immer so ruehmt eine 'ueberraschungsfreie' Sprache zu sein und ausserdem im Gegensatz zu Perl ein komfortables handlen von 2+D-Arrays zu ermoeglichen

wuensche eine anregende Diskussion
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Hallo rer und Willkommen im Forum!
:)
rer hat geschrieben: >>>x=[['a0','a1'],['b0','b1']]
>>> x[:][1]
['b0', 'b1']
Also ich will ja jetzt nichts sagen... aber erklär mir mal bitte, warum du a1 und b1 erwartet hast? Damit erhälst du sozusagen

Code: Alles auswählen

['a0', 'a1'], ['b0', 'b1']
Und hier greifst du wieder *ganz normal* auf die erste Stelle ([0]) und die zweite stelle ([1]) zu.

Also ganz normal dein Ergebnis. Hat nichts mit Design/Implementierungsfehler zu tun. Also freue ich mich nicht auf eine nicht anregende, sinnlose Diskussion.

Ich beschaeftige mich seit ca. 1 Monat mit python, habe bisher sehr viel in Perl gemacht und muss doch feststellen, das python einige Implementierungs- wenn nicht gar Designfehler hat.
Vielleicht sind es auch einfach ein paar Denkfehler deinerseits gewesen.

MfG EnTeQuAk
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Ich glaube, das was rer erwartet, kommt aus MatLab.

rer, dein x ist weder ein Array noch eine Matrix, sondern eine Liste von Objekten. Nichts weiter. Und da macht das von Ente erklaerte Verhalten Sinn. Du musst die Eckigen Klammern von Links nach Rechs lesen, und [:] tut nichts weiter, als eine Kopie eine Liste zu erzeugen, und auf diese Liste wendest du dann [1] an. Also in langform:

Code: Alles auswählen

a = x[:]
a[1]
Hier sieht man doch, dass das Verhalten ganz natuerlich ist, kein Designfehler.

Die Funktionsweise, die du dir vorstellst, ist schon sehr speziell, denn das die Items einer Liste alle wieder aus (gleichlangen) Listen bestehen, kommt ja eher selten vor. Das von dier erwartete Verhalten macht nur in dem Spezialfall Sinn, dass du die Liste als Matrix verwenden willst. Fuer mathematische Verwendungen waere vielleicht numpy/scipy eher was fuer dich?
rer
User
Beiträge: 5
Registriert: Samstag 19. Mai 2007, 14:13

Hallo EnTeQuAk,

das verstehe ich schon wenn man das als Verkettung von Ausdruecken versteht, nur wuerde ich mir das von dir geschilderte Ergebnis eher von einem Konstrukt wie (X[:])[1] versprechen. Im Sinne einer logischen, konsequenten und vollstaendigen Array/Listen/Matrixzugriffssyntax wuerde ich mir aber trotzdem mein erwartetes Ergebnis versprechen, ansonsten hat Python eben keine solche Geradlinigkeit in diesem Zusammenhang
@rebecca: numpy kenne ich und nutze es auch, trotzdem wuerde ich wuenschen, wenn eine solche Syntax im Kern implementiert waere, bei unterschiedlich langen sub-Listen koennte bei Luecken ja None zurueckgegeben werden
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Hallo EnTeQuAk,

das verstehe ich schon wenn man das als Verkettung von Ausdruecken versteht, nur wuerde ich mir das von dir geschilderte Ergebnis eher von einem Konstrukt wie (X[:])[1] versprechen. Im Sinne einer logischen, konsequenten und vollstaendigen Array/Listen/Matrixzugriffssyntax wuerde ich mir aber trotzdem mein erwartetes Ergebnis versprechen, ansonsten hat Python eben keine solche Geradlinigkeit in diesem Zusammenhang
Du wirfst hier mit Begriffen um dich. Matrix, Listen, Arrays... Schlag mich tot... aber die haben nicht wirklich viel miteinander zu tun.

Code: Alles auswählen

>>> l = [['a', 'b'], ['c', 'd']]
>>> (l[:])[1] == l[:][1]
True
Das ist ja auch das feine an Python. Man muss kaum maskieren(hieß das so) und mit Klammern arbeiten. Es fasst das meißt selber sehr intellegent zusammen.
ansonsten hat Python eben keine solche Geradlinigkeit in diesem Zusammenhang
Erklär mir mal, was du mit Gradlinigkeit meinst.

Beispiele helfen hier besser weiter. Vielleicht können wir dir dann besser helfen.

MfG EnTeQuAk
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

rer hat geschrieben:ansonsten hat Python eben keine solche Geradlinigkeit in diesem Zusammenhang
Mmh, mal sehen:

Code: Alles auswählen

a = [funktion1, funktion2, funktion3]
a[1](param1, param2)
funktion4(param1, param2)[5]
funktion5(param1, para,3)(param3,  param4)
# ...
In diesem Zusammenhang istalles andere als

Code: Alles auswählen

x = [[1, 2], [3, 4]]
x[:][1]  # ->  [3, 4]
eine Ausnahme von der Regel.

Listen sind keine Matrizen. Punkt.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

rer hat geschrieben:wenn eine solche Syntax im Kern implementiert waere, bei unterschiedlich langen sub-Listen koennte bei Luecken ja None zurueckgegeben werden
Das ist aber auch nicht gerade Gradlinig wenn was zurück gegeben wird was nicht in den Listen an entsprechenden Positionen vorhanden ist.
Eine Matrix sollte im gesamten initialisiert sein a x b

Wenn du eben die Elemente haben willst, wie oben beschrieben, nutze doch
die line-comprehension:

Code: Alles auswählen

>>> x = [["a0","a1"],["b0","b1"]]
>>> [ e[1] for e in x ]
['a1', 'b1']
Birgt allerdings die Gefahr das bei ungleichen Listen der Indexzugriff ins leere greift und dir ne Exception um die Ohren haut.

Oder nimm Matrixklassen wenn echt Matrizen benötigt werden, aber keine Listen
rer
User
Beiträge: 5
Registriert: Samstag 19. Mai 2007, 14:13

Es ist ja nicht so das ich mein Problem nicht mit Paketen wie numpy nicht elegant loesen koennte, insofern ist die Diskussion nur akademisch, sollte sie uebrigens von Anfang an auch nur sein. Was mich nur wundert, ist weil die meisten Programmiersprachen ja den Zugriff auf mehrdimensionle Arrays, oder nennen wir es Tabellenn oder Zeilen/Spalten-Strukturen, damit keine Begriffsverwirrung aufkommt, in der Form x[a] oä bieten, was ja schliesslich auch die weitaus haeufigste Form der Datenanordnung ist (Tabellen,Grids,Spreadsheets,Datenbanken). Python bietet das auf den ersten Blick auch, aber nur auf den ersten und auch nicht durchgaengig, weil das eben als referenzierte Listen implementiert ist. Ausserdem wird in fast jedem Python-Tutorial suggeriert, dass Python mehrdimensionale Arrays unterstuetzt (im Gegensatz zu Perl), was ja wohl definitiv nicht stimmt (zumindest builtin). Ich wollte halt nur nicht fuer solche Alltagsaufgaben gleich ein dickes Numpy-modul mit mir rumschleppen, und dachte, das das auch einfacher geht.

@zap: was sind Matrix-Klassen? ist das das array-Modul aus der Standard-lib, und kann man damit Spalten slicen?
BlackJack

@rer: Also das mit dem Geradlinig verstehe ich auch nicht. ``obj[a]`` bedeutet so wie es jetzt implementiert ist *immer* hole das Objekt an Index `a` von Objekt `obj` und von *dem* Objekt dann das Objekt an Index `b`.

Du möchtest nun also das nicht so ``(obj[a])`` geklammert wird, sondern so ``obj([a])``. Dafür hätte ich jetzt gerne mal eine semantische Beschreibung was bei Indexoperator auf Indexoperator angewendet passieren soll. Und dass bitte nicht für so spezielle Objekte wie Matrizen sondern für *allgemeine* Objekte `obj`, so dass Deine Beschreibung auch für verschachtelte Abbildungen, Listen oder sonstwas gilt und trotzdem noch so einfach und geradeheraus beschrieben und angewendet werden kann, wie das jetzt der Fall ist.

Ach und Dir ist klar, dass ``obj[a]`` im Grunde nur syntaktischer Zucker für ``obj.__getitem__(s).__getitem(b)`` ist und dass man diese Methode bei eigenen Objekten ganz einfach überschreiben kann, um das Verhalten zu implementieren!? Wenn Du Deine Semantik erklärst, dann beschreibe bitte auch gleich wie man Dein Verhalten genauso einfach selbst implementieren und Anpassen kann.

Von welchen anderen Programmiersprachen redest Du da? Die meisten gebräuchlichen haben kein Slicing wie von Dir gewünscht. C, C#, C++, Java, Pascal haben das alle nicht. Eher "Spezialsprachen" wie Matlab oder IDL. Oder auch Python mit Objekten, die so etwas implementieren.

Zweidimensionale "Arrays" mit ``obj[a]`` kann man mit verschachtelten Listen realisieren. Im Gegensatz zu Perl ist das einfacher weil man sich nicht explizit mit Referenzen befassen muss. Und diese verschachtelten Listen funktionieren im Grunde nicht anders als mehrdimensionale Arrays in C#, Java und Co. Auf ganze Zeilen kann man recht einfach zugreifen, Werte einer Spalte muss man in einer Schleife ansprechen.

So häufig ist aber so eine Datenstruktur auch nicht, jedenfalls nicht wenn man OOP programmiert. Eine DB-Tabelle würde dann eher in einer Liste von Objekten, die aus den Daten einer Zeile gebildet werden, bestehen oder aus einer Abbildung (Schlüssel, Objekt aus Zeile).
rer
User
Beiträge: 5
Registriert: Samstag 19. Mai 2007, 14:13

so wie die Python-(Pseudo)Matritzen als verschachtelte Listen implementiert sind, und nicht als eigene Datentypen mit eigenen Operatoren, scheint es tatsaechlich etwas schwierig zu sein eine solche Zugriffssyntax zu implementieren, ohne den Komfort der normalen Listsyntax zu opfern. Ich werd mal versuchen eine Klasse zu entwickeln, die durch ueberladen von __getitem ueber list-comprehensives die Spalten ausspuckt

Danke fuer die Denkanstoesse
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

Vielleicht wirkt ja mein Morgenkaffee noch nicht, aber ich muss jetzt tatsächlich mal zugeben, dass ich das Problem immernoch nicht verstanden hab. Ich finde das Verhalten im Beispiel ebenfalls vollkommen überraschungsfrei.
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

In MatLab funktioniert das halt ein bisschen anders: wenn du eine Matrix A hast,

Code: Alles auswählen

1 2 3
4 5 6
kannst du so etwas machen:

Code: Alles auswählen

A(1, 2)  -> 2
A(1, 2:3) -> 2, 3
A(:, 1)  -> erste Spalte
A(:, 1:2) -> Teilmatrix (erste und zweite Spalte)
Bei MatLab hat man eben keine Verkettung wie bei [][], sondern der erste Parameter beim Aufruf gibt den Bereich fuer die Reihenindices an, der zweite Paramter den Bereich fuer die Spaltenindices.

Das macht fuer Matrizen in einem numerischen Tool ja auch Sinn, ist halt was komplett anderes als verschachtelte Listen in einer allgemeinen Programmiersprache. Matlab traegt die Matrizen ja auch schon im Namen... :)
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

Ah, jetzt hab ich mir das Eingangsbeispiel nochmal angesehen und habs auch kapiert. :-) Danke Rebecca, danke Koffein! :-D
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
Antworten