hallo zusammen ich habe eine Frage : wie kann man mit Python programm durch dictionary doppelte zeilen entfernen so dass es nur eine zeile von diesen 2 bleiben
Danke im voraus
ich werde mich sehr freuen wenn jemand mir hilfe kann
Doppelte Zeilen entfernen
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Falls man die Zeile nicht wieder direkt in eine Datei schreibt - dann kann man sich die Liste natürlich auch sparen.snafu hat geschrieben:Bzw mit einem Set und einer Liste, falls die Reihenfolge der Zeilen (bezogen auf deren erstes Auftreten) erhalten bleiben soll.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Richtig. Oder man abstrahiert das erstmal als eine kleine Generator-Funktion. Je nachdem, was man halt haben möchte.Hyperion hat geschrieben:Falls man die Zeile nicht wieder direkt in eine Datei schreibt - dann kann man sich die Liste natürlich auch sparen.snafu hat geschrieben:Bzw mit einem Set und einer Liste, falls die Reihenfolge der Zeilen (bezogen auf deren erstes Auftreten) erhalten bleiben soll.
Jetzt seid doch mal nicht so unflexibel... Wenn man will, dann kann man das auch mit einem Dictionary lösen:
mutetella
Code: Alles auswählen
def unique(iterable):
iterable = list(iterable)
lookup = dict(enumerate(iterable))
for index in lookup:
occurences = iterable.count(lookup[index])
if occurences > 1:
for _ in range(occurences - 1):
iterable.pop(iterable.index(lookup[index]))
return iterable
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit
)

- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Tse tse tse... du hättest Dir wenigstens noch die Mühe machen können, uns die Laufzeit von Deinem obfuscated "Meisterwerk" zu nennen 

encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@Hyperion
Wollte ich eigentlich gleich nachreichen, aber `timeit` läuft immer noch...
Wollte ich eigentlich gleich nachreichen, aber `timeit` läuft immer noch...

Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit
)

Nachdem wir etwas ähnliches erst kürzlich in diesem Thread hatten, hat mich das jetzt doch noch gebitz'lt, wie eine sinnvolle
Lösung mit einem Dictionary wohl abschneidet:
Natürlich lässt das hier wieder jeden kalt, weil's ja eh klar war und gar nicht anderst sein kann
. Ich allerdings hätte das nicht erwartet...
mutetella

Code: Alles auswählen
def unique_with_list(test):
result = []
for element in test:
if not element in result:
result.append(element)
return result
def unique_with_set(test):
seen = set()
result = list()
for item in test:
if item not in seen:
result.append(item)
seen.add(item)
return result
def unique_with_dict(test):
unsorted = {}
for index, element in enumerate(test):
unsorted.setdefault(element, index)
return [item[0] for item in sorted(unsorted.items(), key=lambda i: i[1])]
def unique_with_dict_1(test):
unsorted = {}
for index, element in enumerate(test):
unsorted.setdefault(element, index)
result = [None for _ in xrange(len(unsorted))]
for item in unsorted.iteritems():
result[item[1]] = item[0]
return result
Code: Alles auswählen
In [11]: test = [
....: ''.join(random.choice(string.ascii_letters) for
....: _ in range(3)) for _ in range(200)
....: ]
In [12]: timeit unique_with_list(test)
1000 loops, best of 3: 268 µs per loop
In [13]: timeit unique_with_set(test)
10000 loops, best of 3: 56.3 µs per loop
In [14]: timeit unique_with_dict(test)
10000 loops, best of 3: 141 µs per loop
In [15]: timeit unique_with_dict_1(test)
10000 loops, best of 3: 86.4 µs per loop


mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit
)

Lösung "unique_with_dict_1" ist nicht nur unpythonisch, sondern auch fehlerhaft. Index kann bis len(test)-1 gehen, result hat aber nur die Länge von unsorted. Und ja, es ist klar dass dict langsamer ist als set, da das dict extra noch sortiert werden muß.
@mutetella: Anmerkungen:
Es fehlt auch noch die IMHO naheliegenste Variante das Wörterbuch einfach als Menge zu verwenden:
Bei der Liste hätte ich den ``not in``-Operator verwendet. Das sind zwar zwei Worte, aber das ist *ein* Operator, im Gegensatz zu ``not a in b`` wo man erst den ``in``-Operator verwendet und danach das Ergebnis mit ``not`` negiert.
Code: Alles auswählen
result = [None for _ in xrange(len(unsorted))]
# =>
result = [None] * len(unsorted)
Code: Alles auswählen
def unique_with_dict_2(items):
seen = dict()
result = list()
for item in items:
if item not in seen:
result.append(item)
seen[item] = item
return result
... sondern auch nicht wirklich ernst gemeint...Sirius3 hat geschrieben:Lösung "unique_with_dict_1" ist nicht nur unpythonisch, ...

Ja, `index` kann bis ``len(test) - 1`` gehen, aber `result` soll ja immer nur so groß wie `unsorted` sein. Oder verstehe ich Dich falsch?Sirius3 hat geschrieben:... sondern auch fehlerhaft. Index kann bis len(test)-1 gehen, result hat aber nur die Länge von unsorted.
Das bringt tatsächlich auch nochmal was...BlackJack hat geschrieben:Code: Alles auswählen
result = [None for _ in xrange(len(unsorted))] # => result = [None] * len(unsorted)
Code: Alles auswählen
In [6]: timeit equal_items.unique_with_dict_1_lc(equal_items.test)
10000 loops, best of 3: 84.8 µs per loop
In [7]: timeit equal_items.unique_with_dict_1_mul(equal_items.test)
10000 loops, best of 3: 76.6 µs per loop
Die dann tatsächlich schneller als die `set`-Variante ist:BlackJack hat geschrieben:Es fehlt auch noch die IMHO naheliegenste Variante das Wörterbuch einfach als Menge zu verwenden:
Code: Alles auswählen
In [10]: timeit equal_items.unique_with_set(equal_items.test)
10000 loops, best of 3: 56.9 µs per loop
In [11]: timeit equal_items.unique_with_dict_2(equal_items.test)
10000 loops, best of 3: 44.8 µs per loop

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit
)

- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Das überrascht mich schon ein wenig - ich hätte da ja auf quasi Gleichstand getippt... (beides Hash basiert; sofern beide Implementierungen die selben Mechanismen nutzen, sollte es da doch zeitlich keinen Unterschied geben‽)mutetella hat geschrieben:Die dann tatsächlich schneller als die `set`-Variante ist:BlackJack hat geschrieben:Es fehlt auch noch die IMHO naheliegenste Variante das Wörterbuch einfach als Menge zu verwenden:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Kürzeren Code bekommt man ja so.
Die Performance habe ich jetzt nicht getestet, dürfte aber relativ schlecht sein.
Code: Alles auswählen
def unique_with_ordered_dict(test):
return list(collections.OrderedDict.fromkeys(test))
@Hyperion: Ich vermute mal ganz stark das liegt an der Implementierung weil bei einem ``a[x] = x`` der Compiler schon erkennen kann welche Methode hier aufgerufen wird, im Gegensatz zu ``a.add(x)`` wo wahrscheinlich tatsächlich erst einmal, und jedes mal, die `add()`-Methode vom Objekt abgefragt wird. Wenn man sich das mal als Bytecodes anschaut:
Würde ich also als Implementierungsdetail ansehen: Bei anderen Implementierungen könnte die Attributzuweisung langsamer sein wenn sie nicht als Sonderfall behandelt wird, und andererseits könnte ich mir vorstellen, dass eine Implementierung den zweiten Fall auch optimieren könnte.
Code: Alles auswählen
In [1]: def f():
...: a[x] = x
...: b.add(x)
...:
In [2]: import dis
In [3]: dis.dis(f)
2 0 LOAD_GLOBAL 0 (x)
3 LOAD_GLOBAL 1 (a)
6 LOAD_GLOBAL 0 (x)
9 STORE_SUBSCR
3 10 LOAD_GLOBAL 2 (b)
13 LOAD_ATTR 3 (add)
16 LOAD_GLOBAL 0 (x)
19 CALL_FUNCTION 1
22 POP_TOP
23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Ja, daran sollte es liegen. Wird die Auflösung von add herausgezogenBlackJack hat geschrieben:@Hyperion: Ich vermute mal ganz stark das liegt an der Implementierung weil bei einem ``a[x] = x`` der Compiler schon erkennen kann welche Methode hier aufgerufen wird, im Gegensatz zu ``a.add(x)`` wo wahrscheinlich tatsächlich erst einmal, und jedes mal, die `add()`-Methode vom Objekt abgefragt wird.
Code: Alles auswählen
def unique_with_set_2(test):
seen = set()
result = list()
add = seen.add
for item in test:
if item not in seen:
result.append(item)
add(item)
return result
Code: Alles auswählen
In [2]: timeit unique_with_set_2(test)
10000 loops, best of 3: 40.7 µs per loop
In [3]: timeit unique_with_dict_2(test)
10000 loops, best of 3: 40.8 µs per loop
Das Leben ist wie ein Tennisball.
@/me
`OrderedDict` hatte ich anfangs auch gleich im Sinn, war aber wie Du vermutest von der Performance unter ferner liefen...
mutetella
`OrderedDict` hatte ich anfangs auch gleich im Sinn, war aber wie Du vermutest von der Performance unter ferner liefen...
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit
)
