Seite 1 von 1

Datenfile fuer Diagramm einlesen, doppelte Zeilen auslassen.

Verfasst: Montag 19. Oktober 2009, 09:13
von Gabelmensch
Tag,

ich habe einen Datenfile für ein Diagramm, dieser sieht so aus:

Code: Alles auswählen

1 10 0 13 9
2 12 0 13 9
3 12 0 13 9
4 12 5 13 7
5 12 5 14 7
6 12 5 14 7
7 12 4 8 10
8 8 6 8 10
9 8 6 8 10
Die erste Spalte ist eine fortlaufende Nummer, die restlichen sind Datenwerte. Diese Datei lese ich mir in eine "var":

Code: Alles auswählen

infile = open(datei, 'r')
var = map(string.strip, infile.readlines())
infile.close()
Jetzt habe ich alle Zeilen in einer liste:

Code: Alles auswählen

print var
['1 10 0 13 9', '2 12 0 13 9', '3 12 0 13 9', '4 12 5 13 7',
 '5 12 5 14 7', '6 12 5 14 7', '7 12 4 8 10', '8 8 6 8 10',
 '9 8 6 8 10']
Ich moechte jetzt alle untereinander doppelten datenwerte entfernen, dh. am Ende moechte ich soetwas haben:

Code: Alles auswählen

1 10 0 13 9
2 12 0 13 9
4 12 5 13 7
5 12 5 14 7
7 12 4 8 10
8 8 6 8 10
Wie gehe ich am besten vor? Mein Ansatz als n00b waere alle Zeilen in einer for-Schleife einzulesen, in eine eigene Liste splitten:

Code: Alles auswählen

for i in var:
	i = string.split(i)
        print i
['1', '10', '0', '13', '9']
['2', '12', '0', '13', '9']
['3', '12', '0', '13', '9']
['4', '12', '5', '13', '7']
['5', '12', '5', '14', '7']
['6', '12', '5', '14', '7']
['7', '12', '4', '8', '10']
['8', '8', '6', '8', '10']
['9', '8', '6', '8', '10']

Jetzt koennte ich abfragen ob z.B. i[2] mit dem alten i[2] in einer Hilfsvariable identisch ist, jedoch glaube ich es gibt noch einen besseren Weg.

Hinzu kommt, die Datenfiles sind unterschiedlich breit, manchmal 3 Spalten und manchmal 10 Spalten. Wie wuerdet ihr vorgehen?

Verfasst: Montag 19. Oktober 2009, 09:16
von Hyperion
Das ist schön für Dich. :-)

Wo ist jetzt aber die Frage? ;-)

Verfasst: Montag 19. Oktober 2009, 09:30
von Gabelmensch
Hyperion hat geschrieben:Das ist schön für Dich. :-)

Wo ist jetzt aber die Frage? ;-)
Das Baustellenschild nicht gesehen? :)

Verfasst: Montag 19. Oktober 2009, 09:40
von jbs

Code: Alles auswählen

cache = set()
lines = []
with open 'file' as f:
    for line in f:
        i, data = line.split(' ',1)
        if data in cache:
            continue
        cache.add(data)
        lines.append(line)
ungetestet

Verfasst: Montag 19. Oktober 2009, 09:45
von Hyperion
Gabelmensch hat geschrieben:
Hyperion hat geschrieben:Das ist schön für Dich. :-)

Wo ist jetzt aber die Frage? ;-)
Das Baustellenschild nicht gesehen? :)
Nicht wirklich ;-)

Es kommt natürlich für die Praxis schon darauf an, wie groß Deine Datenfiles sind.

Die triviale Methode hat halt eine quadratische Laufzeit: Du nimmst Dir den ersten Listeneintrag und vergleichst auf Gleichheit mit allen anderen. Bei Gleichheit wird gerade iterierte Eintrag gelöscht.
Das ist recht simpel zu implementieren, aber auch von der Laufzeit grottig.

Eine Alternative lehnt sich an den zip-Algorithmus an. Du iterierst über die Liste und baust mit den Werten Schritt für Schritt einen Baum auf. D.h. Du hast einen (abstrakten) Wurzelknoten und fügst dann für jeden Wert einen Knoten hinzu, der durch eine Kante mit dem jeweiligen Vorgängerwert verbunden ist. Ganz am Ende kannst Du Dir dann noch den Index der Zeile merken, sollte das wichtig sein.
Ist nun eine Zeile doppelt in der Liste, so wird diese exakt den gleichen Ast aufbauen, wie Du ihn schonv orher angelegt hast.
Ganz am Schluss musst Du nur noch den Baum traversieren und erhältst damit alle verschiedenen Einträge.

Verfasst: Montag 19. Oktober 2009, 09:47
von CM
Vielleicht

Code: Alles auswählen

line.append(map(int, data.split()))
? Hängt ein bißchen davon ab, wie Du weiter vorgehen willst.

Verfasst: Montag 19. Oktober 2009, 10:10
von Gabelmensch
jbs hat geschrieben:

Code: Alles auswählen

cache = set()
lines = []
with open 'file' as f:
    for line in f:
        i, data = line.split(' ',1)
        if data in cache:
            continue
        cache.add(data)
        lines.append(line)
ungetestet
Vielen Dank, es hat mir geholfen:

Code: Alles auswählen

cache = []
fertig = []
for i in var:
#	print i
	i = string.split(i)
#	print i[1:]
	
	if i[1:] == cache:
		print "gleich"
	else:
		print "ungleich"
		fertig.append(i)

	cache = i[1:]
#	print cache

print "-------------"

print fertig
Und auch dickes Danke an alle anderen, ich schaue mir eure Beiträge auf jedenfall noch genauer an.

Verfasst: Montag 19. Oktober 2009, 10:21
von Gabelmensch
Hyperion hat geschrieben:
Die triviale Methode hat halt eine quadratische Laufzeit: Du nimmst Dir den ersten Listeneintrag und vergleichst auf Gleichheit mit allen anderen. Bei Gleichheit wird gerade iterierte Eintrag gelöscht.
Das ist recht simpel zu implementieren, aber auch von der Laufzeit grottig.
Naja, sie sollen ja nur untereinander unterschiedlich sein, ist vielleicht etwas ungluecklich formuliert. Zeile 5 soll nicht mit Zeile 4 identisch sein. Wenn 4 und 6 identisch sind, aber 5 nicht, ist es OK.

Verfasst: Montag 19. Oktober 2009, 10:47
von jbs
Gabelmensch hat geschrieben:
Vielen Dank, es hat mir geholfen:

Code: Alles auswählen

cache = []
fertig = []
for i in var:
#	print i
	i = string.split(i)
#	print i[1:]
	
	if i[1:] == cache:
		print "gleich"
	else:
		print "ungleich"
		fertig.append(i)

	cache = i[1:]
#	print cache

print "-------------"

print fertig
Und auch dickes Danke an alle anderen, ich schaue mir eure Beiträge auf jedenfall noch genauer an.
Die Benennung der Variablen ist unglücklich. ``i`` wird für Index o.ä. verwendet. Statt ``string.split(s)`` solltest du ``s.split()`` verwenden.
Möchtest du es nur mit der vorherigen Reihe vergleichen?

Ein Blick in PEP 8 könnte auch nicht schaden :).

Verfasst: Montag 19. Oktober 2009, 11:18
von Gabelmensch
jbs hat geschrieben: Ein Blick in PEP 8 könnte auch nicht schaden :).
Jepp, aber erst wenn ich Zeit habe, jetzt halte ich mich an Murphys Ueberlebensregel Nr 1 "Wenn etwas dumm ist, aber funktioniert, ist es nicht dumm". Momentan habe ich Urlaub und schreibe ein ziemlich dickes Bashscript in Python neu. Vor letzter Woche, habe ich noch keine Zeile Python geschrieben. :!:

Verfasst: Montag 19. Oktober 2009, 12:34
von BlackJack
@Gabelmensch: Wenn man das nicht *gleich* oder zumindest *sehr* zeitnah richtig macht, dann wird das nie etwas. So vorhaben wie "Das überarbeite ich dann noch einmal, wenn es fertig ist." werden erfahrungsgemäss selten bis nie umgesetzt. Das endet damit, dass Du dann das grosse Bash-Skript mit nichtssagenden und irreführenden Namen "übersetzt" hast, danach nichts mehr daran änderst, weil es ja läuft und keine Zeit mehr ist. Und nach einem Jahr verstehst Du dann Dein eigenes Programm nicht mehr, bzw. musst beim reinlesen in den Quelltext viel mehr Gehirnschmalz aufbringen um die Bedeutungen der einzelnen Namen wieder heraus zu finden.

Verfasst: Montag 19. Oktober 2009, 13:41
von Gabelmensch
In 1-1,5 Jahren ueberarbeite ich es sowiso nochmal komplett, weil ich dann Python besser draufhabe, und es mir deshalb zu langsam ist. Um jetzt wirklich die Tricks und Kniffe zu lernen brauche ich zuviel Zeit. Dann kommt auch Python 3 in meine Distribution. Vorgestern habe ich die Aenderungen durchgelesen, und mein jetziger Code ist teilweise inkomatibel. :mrgreen:

Verfasst: Montag 19. Oktober 2009, 14:00
von BlackJack
@Gabelmensch: Den Übergang kann man versuchen so weit wie möglich zu automatisieren. Es gibt ein `2to3.py`-Skript, was vieles automatisch anpassen kann. Bei Python >=2.6 kann man auch einiges von Python 3.x über `__future__`-Importe aktivieren, um den Übergang "sanfter" zu gestalten.

Ob in 1½ Jahren wirklich schon 3.x vollständig "übernommen" hat, wird sich zeigen. Python 2.x soll jedenfalls AFAIK noch bis 2.9 gehen, und der Release-Zyklus ist ca. 18 Monate.