Aus einer Liste doppelte Einträge entfernen (Einzeiler)

Code-Stücke können hier veröffentlicht werden.
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

*hehe*, das kommt schon noch :wink: Die schönste und resourcenspaarenste ist die von Voges auf 2.4 übersetzt. Bei der bleibt dann die Sortierung auch erhalten, was sehr vorteilhaft sein kann. Deswegen nehm ich weder dicts noch sets (welche ja auch nur dicts mit speziellen Methoden sind)

Code: Alles auswählen

(item for (i,item) in enumerate(longList) if item not in longList[:i])
Dumm nur, das longList selbst kein Iterator sein kann, da die kein slicing unterstützen.
Clython
User
Beiträge: 151
Registriert: Samstag 21. August 2004, 13:58
Wohnort: Schweiz, BE-2500

Tja mir ist im nachhinein aufgefallen, dass ich so dumm gar nicht bin, da mein Code die Liste flattet aber gleichzeitig auch das Vorkommen der einzelnen Tokens zählt (brauchte den Algorithmus für meinen Tokenizer). Hier mal der Code, Verbesserungsvorschläge gerne gesehen:

Code: Alles auswählen

def count_words(liste):
	liste.sort()
	current_pos = 0
	first_pos = 0
	out_liste = []
	nr_liste = []
	list_length = len(liste)
	word = liste[current_pos]
	while current_pos <= list_length:
		if current_pos < list_length:
			new_word = liste[current_pos]
			if word != new_word:
				last_pos = current_pos - 1
				anzahl_vorkommen = last_pos - first_pos
				out_liste.insert(0, word)
				nr_liste.insert(0, [word, anzahl_vorkommen + 1])
				first_pos = current_pos
				word = liste[current_pos]
		else:
			last_pos = current_pos - 1
			anzahl_vorkommen = last_pos - first_pos
			out_liste.insert(0, word)
			nr_liste.insert(0, [word, anzahl_vorkommen + 1])
		current_pos = current_pos + 1
	out_liste.reverse()
	nr_liste.reverse()
	return out_liste, nr_liste, list_length
Edit by Dookie: Code in Pythontags gesetzt
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

hier mal meine Version, unter Einbeziehung vorhandener Lösungen.

Code: Alles auswählen

def count_words2(liste):
    out_liste = [item for (i,item) in enumerate(liste) if item not in liste[:i]]
    nr_liste = [[item, liste.count(item)] for item in out_liste]
    list_length = len(liste)
    return out_liste, nr_liste, list_length
Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
joe

Auch wenn ich nicht ganz verstaqnden habe, was cpythons count_words leisten soll:

Code: Alles auswählen

def count_words3(liste):
    wc = {}
    for w in liste:
        wc[w] = 1 + wc.get(w,0)
    return wc.keys(),wc.items(),len(liste)
Das resultat ist zumindest sehr ähnlich.
joe
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

ich hab auch noch eine Alternative, diesmal mit Set.

Code: Alles auswählen

from sets import Set # für Pythonversion < 2.4

def count_words3(liste):
    nr_liste = [[item, liste.count(item)] for item in Set(liste)]
    out_liste = [item for item, nr in nr_liste]
    list_length = sum([nr for item, nr in nr_liste])
    return out_liste, nr_liste, list_length
Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
joe

Etwas "umformuliert":

Code: Alles auswählen

from sets import Set
def count_words3(liste):
    out_liste = list(Set(liste))
    nr_liste = [(w,liste.count(w)) for w in out_liste]
    return out_liste, nr_liste, len(liste) 
joe
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ihr seit aber schon ziemlich offtopic, Dookie selbst hat im letzten Post sechs Zeilen zu viel gehabt ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

um zu Clythons Version zurückzukommen, hab ich die auch mal etwas optimiert.

Code: Alles auswählen

def count_words4(liste):
    liste.sort()
    first_pos = 0
    current_pos = 0
    out_liste = []
    nr_liste = []
    list_length = len(liste)
    if not list_length: # nothing to do
        return out_liste, nr_liste, list_length
    word = liste[0]
    for current_pos in xrange(1, list_length):
        new_word = liste[current_pos]
        if word != new_word:
            last_pos = current_pos - 1
            anzahl_vorkommen = last_pos - first_pos
            out_liste.append(word)
            nr_liste.append([word, anzahl_vorkommen + 1])
            first_pos = current_pos
            word = new_word
    else:
        last_pos = current_pos
        anzahl_vorkommen = last_pos - first_pos
        out_liste.append(word)
        nr_liste.append([word, anzahl_vorkommen + 1])
    return out_liste, nr_liste, list_length
1. und auffälligste Änderung, statt einer Whileschleife und hochzählen einer variable mit var += 1 ist eine Forschleife mit xrange effektiver. Hier kann mit 1 begonnen werden, da das erste Wort ohnehin schon vor der Schleife ausgelesen wird.
2. Verwendung von else bei der Forschleife. Das Else wird ausgeführt, wenn die Schleife fertig durchlaufen wurde. Erspart eine if-Abfrage in der Schleife.
3. statt word = liste[current_pos] ist es effektiver auf die lokale Variable new_word mit word = new_word zuzugreifen.
4. verwendung von list.append(word) statt list.insert(0,word), spart auch das list.reverse() am Ende.

Das Ganze ist auch als Anregung gedacht für allgemeine Optimierungen.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Hi. Naja, ist ja auch klar, dass das ganze schneller wird, wenn man mit mehreren Variablen arbeitet. Aber gefragt waren ja Einzeiler gefragt, sonst optimieren wir uns noch in den negativen Bereich :wink:

Btw: wieso verwendest du nochmal else? Der Teil wird in jedem Fall ausgeführt, da in der Schleife kein break steht...
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

jo dat läuft auch ohne else, aber so ists IMHO besser ersichtlich, daß der Teil eigentlich noch zur Schleife gehört und tut der Effizienz keinen Abbruch.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Gast

Hallo,

ich bräuchte auch so etwas nur das meine liste listen mit 2 elementen enthält:

l =[['a', 8], ['b', 7], ['a', 8], ['a', 9], ['c', 6], ['b', 2]]

es soll alle doppeleten l[x][0] entfernen elemente,
also nur ein, b, und c stehen lassen, und dabei nur die ersten vorkommen.
das heisst, das 'a' ist dreimal enthalten, das erste vorkommen ['a', 8]
soll behalten werden und die Sortierung idealerweise auch.

nach reduzieren:
also:
[['a', 8], ['b', 7], ['c', 6]]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi gast,

im Prinzip müsstest du beim obigen Script nur die Zeile mit dem if so ändern das word[0] mit new_word[0] verglichen wird, allerdings bleibt dann deine Sortierung nicht bestehen.

Hier eine spezialisierte Funktion:

Code: Alles auswählen

def deldoub1(liste):
    res = []
    tmp = []
    for item in liste:
        if not item[0] in tmp:
            tmp.append(item[0])
            res.append(item)
    return res
Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Gast

Dookie hat geschrieben:Hi gast,

im Prinzip müsstest du beim obigen Script nur die Zeile mit dem if so ändern das word[0] mit new_word[0] verglichen wird, allerdings bleibt dann deine Sortierung nicht bestehen.

Hier eine spezialisierte Funktion:

Code: Alles auswählen

def deldoub1(liste):
    res = []
    tmp = []
    for item in liste:
        if not item[0] in tmp:
            tmp.append(item[0])
            res.append(item)
    return res
Gruß

Dookie
Danke, eigentlich gar nicht so schwierig :roll:
Antworten