Durchlauf durch Liste und Vergleich der Einträge

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.
BlackJack

@Michi_J: Bist Du sicher das Dein Problem nicht schon irgendwer gelöst hat? Das klingt verdächtig nach triangle strips, die man zum Beispiel auch bei OpenGL erzeugt um zusammenhängende Dreiecke effizient zu speichern.

Ansonsten müsstest Du Dir überlegen welche Attribute und Eigenschaften Punkte, Linien, und Dreiecke als Objekte minimal haben müssten. Erst einmal nur um sie zu erstellen und dann um die Dreiecke zu einem Objektgraphen zu verbinden.

Ich würde sie als Wertobjekte implementieren, mit entsprechenden `__cmp__`- und `__hash__`-Implementierungen um sie als Schlüssel in Dictionaries bzw. Elemente in `set()`\s verwenden zu können.
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

Vielleicht folgendermaßen:

Objekt: Dreieck --> besteht aus Linien und Linien aus Punkten (Punkte sind definiert über XYZ)

Eigenschaft: 2 Dreiecke sind benachbart, wenn sie sich 1 Linie teilen

???
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

Tut mir leid, dass ich so hilflos bin, aber ich weiß es wirklich nicht, wie ich vorgehen soll...
Und wie gesagt, ich bedanke mich nochmals bei jedem, der mir hilft.
BlackJack

@Michi_J: Na dann fang doch einfach mal mit dem kleinsten Baustein an. Schreib eine `Point`-Klasse und dann eine Funktion die aus den Daten Punkt-Objekte erstellt. Und dann eine `Line`-Klasse, die aus den Daten und den Punkt-Objekten Linien-Objekte erstellt. Und dann… ich denke das Prinzip sollte klar sein.
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

hmmm...
Kling für mich einfacher als es ist. Aber danke :-) !
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

die Linie Klasse habe ich einmal geschrieben. Ich habe dazu noch eine Frage. Wie würdet ihr die __eq__-Methode schreiben.
V1:

Code: Alles auswählen

class Line(object):
    def __init__(self, fid, points):
        self.fid = fid
        self.points = points
    
    def __eq__(self, other):
        return all(any(s == o for o in other.points) for s in self.points)
V2:

Code: Alles auswählen

return any(self.points[0] == o for o in other.points) and any(self.points[1] == o for o in other.points)
V3:

Code: Alles auswählen

return (self.points[0] == other.points[0] or self.points[0] == other.points[1]) 
            and (self.points[1] == other.points[0] or self.points[1] == other.points[1])
@Michi_J: BlackJack hat ja alle Funktionen zum Umwandeln der Daten schon beschrieben, man muss sie nur noch implementieren...
create_points würde in etwa so aussehen:

Code: Alles auswählen

def create_points(data):
    points = {}
    for point_data in data:
        fid = point_data[1][0][0]
        points[fid] = Point(fid, point_data[1][0][1])
        
        fid = point_data[1][1][0]
        points[fid] = Point(fid, point_data[1][1][1])
    return points
BlackJack

Ich hätte die `Line`-Klasse wohl so implementiert.

Code: Alles auswählen

class Line(object):
    def __init__(self, fid, points):
        self.fid = fid
        self.points = tuple(points)
    
    def __cmp__(self, other):
        return cmp(sorted(self.points), sorted(other.points))
    
    def __hash__(self):
        return hash(tuple(sorted(self.points)))
Wenn man `__eq__` oder `__cmp__` implementiert, sollte man auch `__hash__` implementieren. Falls einem da nichts sinnvolles einfällt, gerne auch als ``raise TypeError('unhashable')``. Dann kracht's wenigstens richtig und versagt nicht auf eher subtile Weise, die einem vielleicht nicht sofort auffällt, wenn man die Objekte in `dict()`\s oder `set()`\s verwendet.

Falls das mit dem Sortieren ein messbares Laufzeitproblem wird, könnte man einen Sortier- und Hash-Schlüssel schon beim erstellen des Objekts anlegen.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Auch auf die Gefahr hin, mich zu wiederholen: Für solche Anwendungen gibt es bereits fertige Implementierungen

Code: Alles auswählen

>>> from shapely.geometry import Polygon
>>> p1 = Polygon([(0,0),(0,2),(1,1)])
>>> print p1.area
1.0
>>> p2 = Polygon([(0,0),(0,2),(-1,-1)])
>>> print p2.area
1.0
>>> p1.touches(p2)
True
>>>
Die GEOS Bibliothek, auf der Shapely aufbaut, ist eine sehr ausgereifte Software, die weit verbreitet in OpenSource GIS Anwendugen ist. Gerade hier, wo es sich doch um eine imho sehr klassische GIS-Problematik handelt, würde sich die Nutzung ja anbieten ...


Hier noch ein Beispiel, wie man die Verwandschaft zwischen zwei Geometrien herausfinden kann. Touches ist auch True, wenn sich nur die Spitzen berühren

Code: Alles auswählen

>>> p3 = Polygon([(0,2),(0,4),(3,1)])
>>> p2.touches(p3)
True
>>> p1.touches(p3)
True
intersection gibt die Art der Verwandschaft preis:

Code: Alles auswählen

>>> i = p1.intersection(p2)
>>> print i
LINESTRING (0.0000000000000000 0.0000000000000000, 0.0000000000000000 2.0000000000000000)
>>> j = p2.intersection(p3)
>>> print j
POINT (0.0000000000000000 2.0000000000000000)
Oder wenn man auf Schmerzen steht die de-9im Matrix

Code: Alles auswählen

>>> p1.relate(p2)
'FF2F11212'
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

Wow, da sind wohl echte Profis am Werk, die ihre Sache verstehen :-)
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

Vielen Dank für all eure Bemühungen und Beiträge!
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

Auf meinem harten und steinigen Weg dorthin Python in seinen Ansätzen zu verstehen - mehr wage ich auch gar nicht - ist mir bei meiner Sortieraufgabe ein weiteres Problem aufgefallen:

Ich habe eine Liste L = ([a,b], [c,d], [b,a], [d,c]) und aus der möchte ich die Liste L1=([a,b], [c,d]) erzeugen, wo also die "umgedrehten" Einträge nicht mehr vorhanden sind.

Kann mir hier vielleicht auch jemand helfen?

Danke!
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Was sind denn a,b,c,d für Datentypen? Zahlen oder Strings oder ...

Im allgemeinen könntest du für deinen Datentyp, wenn es eine eigene Klasse ist, die __hash__ Methode implementieren und dann ein set aus der Liste machen. Obwohl - verrrate erst einmal, was du da für Daten in der Liste hast
BlackJack

@Michi_J: Das kommt auf die Typen an, die `a`, `b`, usw. haben. Wenn die sortier- und hash-bar sind, könnte man die Einträge in `L` in ein sortiertes Tupel umwandeln und mittels eines `set()`\s Buch darüber führen ob man die Werte schon einmal gesehen hat. Und nur dann `L1` hinzufügen, wenn das nicht der Fall war.
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

a, b, c, d sind Zahlen
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

z.B. Liste = [[1,17], [2,1], [17,1], [1,2]]
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

und gleich noch eine Frage hierzu: wenn ich eine Liste hab, die folgendermaßen aufgebaut ist:

Liste = [[1, [X1, Y1, Z1]], [2, [X2, Y2, Z2], [3, [X1, Y1, Z1], [4, [X3, Y3, Z3]]

das heißt, der Eintrag mit der ID = 1 und mit ID = 3 haben dieselben Koordinaten X1, Y1, Z1. Nun möchte ich die ID=3 durch ID=1 ersetzen, da sie ja beide die gleichen Koordinaten haben, sodass meine Liste also folgendermaßen aussieht:

Liste = [[1, [X1, Y1, Z1]], [2, [X2, Y2, Z2], [1, [X1, Y1, Z1], [4, [X3, Y3, Z3]]

vielleicht hat hierzu auch wer eine Idee. Danke auf alle Fälle an alle und für alles! Ohne euch wärs etwas schwer!
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Und wann hörst du auf, mit diesen verschachtelten Listen zu arbeiten? Die ganze letzte Seite ging doch darum, dass du dir endlich vernünftige Datentypen für deine Datenstruktur ausdenkst. Du wirst so _nicht_ glücklich werden :K

Das hier jetzt noch als Denkanstoss ...

Code: Alles auswählen

from shapely.geometry import Point

class Node(object):
    
    def __init__(self, id, geom):
        self.id = id
        self.geom = geom
        
p1 = Node(1, Point(1,1,1))
p2 = Node(2, Point(2,2,2))
p3 = Node(3, Point(1,1,1))
p4 = Node(4, Point(4,4,4))

for pa in (p1,p2,p3,p4):
    for pb in (p1,p2,p3,p4):
        print pa.id, pb.id, pa.geom.equals(pb.geom)

Code: Alles auswählen

1 1 True
1 2 False
1 3 True
1 4 False
2 1 False
2 2 True
2 3 False
2 4 False
3 1 True
3 2 False
3 3 True
3 4 False
4 1 False
4 2 False
4 3 False
4 4 True
Das darf man so nicht 1:1 übernehmen, sondern soll nur Ideen wecken, wie du an die Sache herangehen könntest
Michi_J
User
Beiträge: 110
Registriert: Samstag 7. August 2010, 08:35

@frabron: Danke für deinen Denkanstoß. Das "Abwenden" von verschachtelten Listen hin zu Objektorientierung ist für mich nicht so ganz einfach, da sehr neu. Ihr seit aber alle sehr bemüht um mich, muss ich feststellen und deshalb denke ich, dass ichs auch hinbekommen könnte.

Für meine "verschachtelte" Version gibt es keine Lösung? Oder funktioniert das nur mit Klassen und Funktionen?

Danke auf alle Fälle nochmals für eure Hilfen!

Michi
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Sicher ist es möglich, die Listen in irgendeiner Weise zu verwursten. Es macht aber keinen Sinn, da man das mittels OOP wesentlich übersichtlicher und vor allem nachvollziehbarer gestalten kann (wie man Dir auch schon auf den letzten 7 (?) Thread-Seiten hat versucht zu vermitteln). Ich nehme mal nicht an, dass sich jemand unbezahlt, freiwillig, unnötigerweise die Hirnzellen verdreht, nur damit Dein Listenkrampf funktioniert.

Es ist jetzt der Zeitpunkt gekommen, das Thema ruhen zu lassen, ein Paket Kaffee zu kaufen, die Wasserrechnung zu bezahlen und sich einige Stunden intensivst mit der OOP zu beschäftigen - und zwar nicht anhand Deines aktuellen Problems. Im Anschluss daran (so nach ein oder zwei Wochen) darfst du diesen Thread dann wiederbeleben.

Grüße ... Heiko
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Antworten