Seite 1 von 2
programmierung.in python
Verfasst: Mittwoch 28. Mai 2014, 16:36
von guy12
Hallo ich habe ein frage: ich habe ein Datei oder liste dt=["DK"
"D14"
"D34"
"D14"
"D34"
"D50"
"D81"
"D81"
"D91"
"D91"]
wie kann ich machen mit der Python programm sodass für jede element ich nur eine erhalte , ich meine dt =["Dk","D34","D14","D50","D81","D91"]
Danke im voraus
Re: programmierung.in python
Verfasst: Mittwoch 28. Mai 2014, 17:28
von BlackJack
@guy12: Was hast Du denn nun, eine Datei oder eine Liste? Falls das da der Inhalt einer Datei ist, sieht der *tatsächlich* genau so aus? Und falls ja, wie ist die Datei zustande gekommen?
Re: programmierung.in python
Verfasst: Mittwoch 28. Mai 2014, 19:25
von mutetella
@guy12
Wenn es sich um eine Liste handelt, dann erstellst Du mit dessen Elementen eine neue Liste und fügst jedes Element nur dann hinzu, wenn es noch nicht enthalten ist:
Code: Alles auswählen
>>> dt = ['DK', 'D14', 'D34', 'D14', 'D34', 'D50', 'D81', 'D81', 'D91', 'D91']
>>> def equalize(iterable):
... new = []
... for element in iterable:
... if not element in new:
... new.append(element)
... return new
...
>>> equalize(dt)
['DK', 'D14', 'D34', 'D50', 'D81', 'D91']
Falls die Reihenfolge keine Rolle spielt:
Code: Alles auswählen
>>> dt = ['DK', 'D14', 'D34', 'D14', 'D34', 'D50', 'D81', 'D81', 'D91', 'D91']
>>> list(set(dt))
['D14', 'DK', 'D34', 'D91', 'D81', 'D50']
mutetella
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 15:03
von darktrym
@mutetella: Zu deinem ersten Ansatz, nicht unbedingt günstig hinsichtlich Laufzeit. Ein Dictionary wäre da die bessere Wahl.
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 15:15
von BlackJack
Wenn's auf die Reihenfolge ankommt ist die übliche vorgehensweise:
Code: Alles auswählen
def main():
data = ['DK', 'D14', 'D34', 'D14', 'D34', 'D50', 'D81', 'D81', 'D91', 'D91']
seen = set()
result = list()
for item in data:
if item not in seen:
result.append(item)
seen.add(item)
print result
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 16:05
von snafu
@BlackJack: Wobei man prinzipiell noch ein paar ``add``-Operationen auf dem Set einsparen kann, wenn man sie nicht wie in deinem Beispiel für wirklich jedes Element ausführt, sondern nur dann, wenn der vorherige Test, den du ja ohnehin machst, ergeben hat, dass das Element bisher noch nicht in ``seen`` steckt. Mag sich in den meisten Fällen nicht allzu stark auf die Gesamtlaufzeit ausführen, tut aber auch nicht weh, wenn man's entsprechend ändert.

Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 18:12
von mutetella
Code: Alles auswählen
import sys
import timeit
test = [
'DK', 'D14', 'D34', 'D14', 'D34', 'D50', 'D81', 'D81', 'D91', 'D91'
]
test_1 = '''\
new = []
for element in test:
if not element in new:
new.append(element)
'''
test_2 = '''\
seen = set()
result = list()
for item in test:
if item not in seen:
result.append(item)
seen.add(item)
'''
if __name__ == '__main__':
length = int(sys.argv[1])
test = test * length
print 'test without set: {}'.format(
timeit.timeit(stmt=test_1,
setup='from __main__ import test',
number=10000))
print 'test with set: {}'.format(
timeit.timeit(stmt=test_2,
setup='from __main__ import test',
number=10000))
Code: Alles auswählen
$ python ./equal_items.py 10
test without set: 0.0989220142365
test with set: 0.145992994308
$ python ./equal_items.py 100
test without set: 0.925514936447
test with set: 1.30377697945
$ python ./equal_items.py 1000
test without set: 9.0896999836
test with set: 12.557033062
$ python ./equal_items.py 10000
test without set: 91.0298860073
test with set: 125.113059044
Dann doch überraschend, oder?
mutetella
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 18:23
von BlackJack
@mutetella: Da Du 1. die Verbesserung nicht vorgenommen hast und 2. das nicht in einer Funktion steckt, überrascht es mich jetzt nicht wirklich.
Edit: Und es kommt natürlich auch auf die Anzahl der tatsächlich unterschiedlichen Elemente an.
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 18:26
von Sirius3
@mutetella: überhaupt nicht überraschend. Deine Ergebnisliste ist in jedem Fall 5 Elemente lang. 5 Elemente linear zu durchsuchen braucht eben ein bißchen weniger Zeit als zweimal einen Hash zu ermitteln und zwei Vergleiche. Dass die Zeit linear mit den Wiederholungen Deiner Liste zunimmt ist dann auch wenig überraschend.
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 18:34
von mutetella
@BlackJack
Die Verbesserung reißt's nicht wirklich raus...
Code: Alles auswählen
test_2 = '''\
seen = set()
result = list()
for item in test:
if item not in seen:
result.append(item)
else:
seen.add(item)
'''
Code: Alles auswählen
$ python ./equal_items.py 100
test without set: 0.910356044769
test with set: 1.21818304062
$ python ./equal_items.py 10000
test without set: 90.9470040798
test with set: 121.787957191
... und was Du mit "in einer Funktion steckt" meinst, verstehe ich nicht.
@Sirius3
Ich dachte nur, dass BlackJack's Version performanter sei, da er von "üblicher Vorgehensweise" sprach. Deshalb war ich überrascht.
mutetella
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 18:48
von BlackJack
@mutetella: Es steckt nicht einer Funktion heisst der Code ist nicht in einer Funktion, sondern, naja, ausserhalb einer Funktion. In meinem Code werden mehr Namen aufgelöst und das ist ausserhalb von Funktionen ”teurer” als bei lokalen Namen in Funktionen.
Meine Version ist üblicherweise auch performanter. Klar kann man Fälle finden bei denen sie das nicht ist, aber generell kann man sagen das mit der Liste ist keine gute Idee weil ``a in b`` bei Listen linear von der Länge der Liste abhängt, während es bei Mengenobjekten völlig egal ist wie viele Objekte da schon drin stehen.
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 19:04
von Sirius3
@mutetella: Sets haben einen etwas größeren Overhead, aber der Zugriff ist unabhängig von der Länge:
Code: Alles auswählen
>>> for x in range(10): data=set(range(x));print len(data), timeit.timeit(stmt=lambda: 50 in data, number=1000000)
...
0 0.165304899216
1 0.161346912384
2 0.165688991547
3 0.184131145477
4 0.184000968933
5 0.172278881073
6 0.176582098007
7 0.172767877579
8 0.168383836746
9 0.177536964417
während der Aufwand bei Listen mit der Länge steigt:
Code: Alles auswählen
>>> for x in range(10): data=list(range(x));print len(data), timeit.timeit(stmt=lambda: 50 in data, number=1000000)
...
0 0.164139032364
1 0.178289890289
2 0.211421012878
3 0.227061033249
4 0.257332086563
5 0.271213054657
6 0.296862840652
7 0.32412314415
8 0.342656135559
9 0.360295057297
Hinzu kommt, dass die Variante mit Set ein Operation pro gefundenem Element mehr hat, so dass der Vorteil von Sets nicht schon bei 1 elementigen Listen überwiegt.
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 23:07
von snafu
mutetella hat geschrieben:Die Verbesserung reißt's nicht wirklich raus...
Code: Alles auswählen
test_2 = '''\
seen = set()
result = list()
for item in test:
if item not in seen:
result.append(item)
else:
seen.add(item)
'''
Die Verbesserung war eher so gemeint, dass ein Element in ``seen`` gesteckt werden soll, wenn es noch *nicht* drin ist. Dein Code macht genau das Gegenteil. Er führt damit von der Funktionweise her zu einem völlig anderem Ergebnis. Zudem sind deine Testfälle ziemlich ungünstig gewählt, wie ja auch schon kommentiert wurde.
Re: programmierung.in python
Verfasst: Donnerstag 29. Mai 2014, 23:18
von snafu
Was man übrigens noch machen kann:
Code: Alles auswählen
from itertools import ifilterfalse
def get_unique(elems):
result = []
seen = set()
have_seen = seen.__contains__
for elem in ifilterfalse(have_seen, elems):
seen.add(elem)
result.append(elem)
return result
Die Idee dahinter ist, dass Schleifendurchläufe in reinem Python eingespart werden, weil mittels ``ifilterfalse()`` die bereits gesehenen Elemente aus Python-Sicht übersprungen werden. Ob das tatsächlich soviel bringt, müsste man aber noch testen.
Wenn die ``add``-Operation auf Python-Sets einen Wahrheitswert zurückliefern würde, ob das Element tatsächlich hinzugefügt wurde (nämlich dann, wenn es noch nicht im Set vorhanden war), dann könnte man etwas deutlich Eleganteres mittels ``filter()`` hinbekommen. Der Code würde dann schrumpfen auf:
Code: Alles auswählen
def get_uniques(elems):
seen = set()
return filter(seen.add, elems)
Re: programmierung.in python
Verfasst: Freitag 30. Mai 2014, 07:49
von mutetella
Wer braucht schon einen Kalender...
snafu hat geschrieben:Dein Code macht genau das Gegenteil. Er führt damit von der Funktionweise her zu einem völlig anderem Ergebnis.
Sag' ruhig, wie es ist: Mein Code ist hirnloser Bullshit!! Ich hab's verbessert...
snafu hat geschrieben:Zudem sind deine Testfälle ziemlich ungünstig gewählt, wie ja auch schon kommentiert wurde.
Ich verstehe nur noch nicht ganz, weshalb. Um zu vergleichen muss ich doch auch jedem Test dieselbe Liste geben. Oder meinst Du mit "Testfälle ziemlich ungünstig gewählt" nur das, was BlackJack mit innerhalb vs. außerhalb einer Funktion schreibt?
Code: Alles auswählen
from itertools import ifilterfalse
import sys
import timeit
test = [
'DK', 'D14', 'D34', 'D14', 'D34', 'D50', 'D81', 'D81', 'D91', 'D91'
]
test_01 = '''\
new = []
for element in test:
if not element in new:
new.append(element)
'''
test_02 = '''\
seen = set()
result = list()
for item in test:
if item not in seen:
result.append(item)
seen.add(item)
'''
test_03 = '''\
result = []
seen = set()
have_seen = seen.__contains__
for elem in ifilterfalse(have_seen, test):
seen.add(elem)
result.append(elem)
'''
def unique_01():
new = []
for element in test:
if not element in new:
new.append(element)
def unique_02():
seen = set()
result = list()
for item in test:
if item not in seen:
result.append(item)
seen.add(item)
def unique_03():
result = []
seen = set()
have_seen = seen.__contains__
for elem in ifilterfalse(have_seen, test):
seen.add(elem)
result.append(elem)
if __name__ == '__main__':
length = int(sys.argv[1])
test = test * length
print 'test list outside function: {}'.format(
timeit.timeit(stmt=test_01,
setup='from __main__ import test',
number=10000))
print 'test list inside function: {}'.format(
timeit.timeit('unique_01()',
setup='from __main__ import test, unique_01',
number=10000))
print 'test set outside function: {}'.format(
timeit.timeit(stmt=test_02,
setup='from __main__ import test',
number=10000))
print 'test set inside function: {}'.format(
timeit.timeit('unique_02()',
setup='from __main__ import test, unique_02',
number=10000))
print 'test itertools outside function: {}'.format(
timeit.timeit(stmt=test_03,
setup='from __main__ import test, ifilterfalse',
number=10000))
print 'test itertools inside function: {}'.format(
timeit.timeit('unique_03()',
setup='from __main__ import test, unique_03, ifilterfalse',
number=10000))
Code: Alles auswählen
$ python ./equal_items.py 10
test list outside function: 0.101276159286
test list inside function: 0.100987195969
test set outside function: 0.0632679462433
test set inside function: 0.0638370513916
test itertools outside function: 0.0752058029175
test itertools inside function: 0.0768110752106
$ python ./equal_items.py 100
test list outside function: 0.917196989059
test list inside function: 1.02419400215
test set outside function: 0.458462953568
test set inside function: 0.451676130295
test itertools outside function: 0.550910949707
test itertools inside function: 0.557126998901
$ python ./equal_items.py 1000
test list outside function: 9.1905798912
test list inside function: 9.39835596085
test set outside function: 4.34967303276
test set inside function: 4.43209385872
test itertools outside function: 5.34194898605
test itertools inside function: 5.87611699104
Sind das nun aussagekräftige Tests oder hab' ich euch tatsächlich noch nicht verstanden?
mutetella
Re: programmierung.in python
Verfasst: Freitag 30. Mai 2014, 08:39
von Sirius3
@mutetella: ich werde gern ignoriert

. Nochmal zum Mitlesen: Je länger die Ergebnisliste, desto schlechter schneidet die List-Variante gegenüber der Set-Version ab. Bei Deinen Tests mit 10, 100, 1000 wird aber die selbe Eingangsliste nur 10, 100 oder 1000 mal durchlaufen, die Ergebnisliste ist aber immer die selbe! Ein sinnvoller Test variiert die Anzahl der unterschiedlichen Elemente in der Eingangsliste nicht deren Länge. Dann hast Du nämlich nicht ein lineares Laufzeitverhalten für alle Varianten, sondern bei gleich Listenlänge konstante Laufzeit bei "Set" und lineare bei "List".
Re: programmierung.in python
Verfasst: Freitag 30. Mai 2014, 09:10
von jerch
@mutetella:
Ersetz doch mal Dein `test` durch so etwas und spiel mal mit dem hinteren Rangewert
Code: Alles auswählen
test = [''.join(random.choice(string.ascii_letters) for _ in range(3)) for _ in range(200)]
Wenn Du Dir überlegst, wie Sets und Listen intern ticken, wird auch klar, was da passiert - die angefragten Operationen (suchen, einfügen) haben verschiedene Laufzeiten in der O-Notation und unterschiedliche Kosten für eine Einzeloperation. Z.B. ist Hashen+Suche im Hashbaum zunächst erstmal teuerer als Suche in einer Liste, eben weil Hashen aufwändig ist. Da die Suche in der Liste aber eine schlechtere Laufzeit hat, gibt es einen break-even point - für alle größeren n gewinnt immer der Hashansatz.
Re: programmierung.in python
Verfasst: Freitag 30. Mai 2014, 11:51
von mutetella
@Sirius3
Ich hab' Deine Erklärung nicht ignoriert. Ich verstehe nur den Zusammenhang zwischen `test` und der Ergebnisliste noch nicht. Wenn ich die Zufallsliste aus jerchs Beispiel verwende und mit einer multiplizierten Liste vergleiche...
Code: Alles auswählen
>>> ['aFy', 'Dab', 'HZT'] * 2
['aFy', 'Dab', 'HZT', 'aFy', 'Dab', 'HZT']
>>> [''.join(random.choice(string.ascii_letters) for _ in range(3)) for _ in range(6)]
['xyi', 'erR', 'dew', 'oTU', 'aYF', 'KKO']
... dann hab' ich unter Verwendung der Zufallsliste wahrscheinlich weniger Duplikate, sprich' eine potentiell größere Ergebnisliste.
Sirius3 hat geschrieben:Bei Deinen Tests mit 10, 100, 1000 wird aber die selbe Eingangsliste nur 10, 100 oder 1000 mal durchlaufen, die Ergebnisliste ist aber immer die selbe!
Aber sowohl mit der Zufalls- wie auch mit der multiplizierten Liste ist doch die Ergebnisliste auch immer gleich groß?
Also nicht, dass ich euch nicht glauben würde, zumal die Testergebnisse dasselbe ausdrücken...
Code: Alles auswählen
if __name__ == '__main__':
length = int(sys.argv[1])
test = [
''.join(random.choice(ascii_letters) for
_ in range(3)) for _ in range(length)
]
print 'test list outside function: {}'.format(
timeit.timeit(stmt=test_01,
setup='from __main__ import test',
number=10000))
print 'test list inside function: {}'.format(
timeit.timeit('unique_01()',
setup='from __main__ import test, unique_01',
number=10000))
print 'test set outside function: {}'.format(
timeit.timeit(stmt=test_02,
setup='from __main__ import test',
number=10000))
print 'test set inside function: {}'.format(
timeit.timeit('unique_02()',
setup='from __main__ import test, unique_02',
number=10000))
print 'test itertools outside function: {}'.format(
timeit.timeit(stmt=test_03,
setup='from __main__ import test, ifilterfalse',
number=10000))
print 'test itertools inside function: {}'.format(
timeit.timeit('unique_03()',
setup='from __main__ import test, unique_03, ifilterfalse',
number=10000))
Code: Alles auswählen
$ python ./equal_items.py 10
test list outside function: 0.0219969749451
test list inside function: 0.0241479873657
test set outside function: 0.0340809822083
test set inside function: 0.0344898700714
test itertools outside function: 0.0381298065186
test itertools inside function: 0.0383148193359
$ python ./equal_items.py 100
test list outside function: 0.745640993118
test list inside function: 0.752784013748
test set outside function: 0.312932014465
test set inside function: 0.304243803024
test itertools outside function: 0.329273939133
test itertools inside function: 0.340594768524
$ python ./equal_items.py 1000
test list outside function: 62.3739390373
test list inside function: 62.4985778332
test set outside function: 2.74161219597
test set inside function: 2.68796682358
test itertools outside function: 2.98557090759
test itertools inside function: 3.06113815308
Ich verstehe sehr wohl, dass bei einer umso größeren Ergebnisliste die set-Lösung performanter wird...
Ok, ich glaub' ich hab's geschnallt: Das Problem war nicht, dass jeder Test dieselbe Liste abarbeitete, sondern dass durch die einfache Multiplikation der Eingangsliste letztlich die Ergebnisliste doch dieselbe blieb und dadurch die Listenlösung niemals in den Bereich vordrang, ab dem sie ihren Vorteil gegenüber der Setlösung verlor. Kann man das so sagen?
mutetella
Re: programmierung.in python
Verfasst: Freitag 30. Mai 2014, 12:27
von guy12
guy12 hat geschrieben:Hallo ich habe ein frage: ich habe ein Datei oder liste dt=["DK"
"D14"
"D34"
"D14"
"D34"
"D50"
"D81"
"D81"
"D91"
"D91"]
wie kann ich machen mit der Python programm sodass für jede element ich nur eine erhalte , ich meine dt =["Dk","D34","D14","D50","D81","D91"]
Danke im voraus
ja es ist ein datei die ich durch diese programm geöffnet habe.
Code: Alles auswählen
with open("kurz-ergebnis.csv", "r") as fd:
for line in fd:
splitline=line.split(',');
print splitline[2]
fd.close()
aber wie man weiter macht bis das ergebnis dt=["DK","D34","D14","D50","D81","D91"]
weiss ich nicht
Re: programmierung.in python
Verfasst: Freitag 30. Mai 2014, 12:41
von Hyperion
Bitte benutze als Einrückung vier Leerzeichen anstelle eines Tabulators! (PEP8 sieht das so vor und man kann das in jedem guten Editor einstellen, dass dieser bei Druck auf Tab vier Leerzeichen in das Dokument übernimmt - es ist also *nicht* mehr Tipparbeit)
Das ``fd.close`` ist obsolete, da Du die Datei mittels ``with`` öffnest!
Wo genau hakt es denn? Was steht denn jeweils in ``splitline``?