items aus listen and-verknüpfen...

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.
Antworten
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 24. April 2005, 17:06

Hi...

ich habe mehrere Listen und will das ich nur die Einträge zurück bekomme, die in allen Listen vorkommen.
Ich habe dafür zwar eine Lösung, aber diese scheint mir nicht wirklich optimal:

Code: Alles auswählen

def and_list( data ):
    if len( data ) == 1:
        # Es gibt nur eine, also sind alle Dateien treffer
        return data.values()[0]

    filelist = data.values()

    print "Listen anzeigen:"
    for i in filelist: print i
    print "-"*80

    resultlist = []
    for idlist in filelist:
        for id in idlist:
            if id in resultlist:
                # id schon vorhanden
                continue

            ok = True
            for id2 in filelist:
                if not id in id2:
                    ok = False
                    break
            if ok:
                resultlist.append( id )

    return resultlist

data = {
    "eins" : [36, 37, 38, 39],
    "zwei" : [36, 37],
    "drei" : [32, 33, 34, 35, 36, 37]
}

result = and_list( data )
print "Ergebnis:", result

print "-"*80

result = and_list( {"nureins":[1,2,3]} )
print "Ergebnis:", result
Ausgabe:
Listen anzeigen:
[32, 33, 34, 35, 36, 37]
[36, 37, 38, 39]
[36, 37]
--------------------------------------------------------------------------------
Ergebnis: [36, 37]
--------------------------------------------------------------------------------
Ergebnis: [1, 2, 3]
Die anzahl der Listen variiert und die Inhalte sind nicht unbedingt Zahlen.
Bei meiner Lösung ist es dumm, das immer alle Einträge durchgeganen werden, obwohl dies nicht immer nötig ist. Aber ich weiß noch nicht so recht, wie man es besser Lösen könnte...
Zuletzt geändert von jens am Sonntag 24. April 2005, 19:10, insgesamt 1-mal geändert.

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Sonntag 24. April 2005, 18:47

Hoi Jens,

schau mal im Tutorial unter Sets. Bietet das alles was Du suchst?

Gruß,
Christian
joe

Sonntag 24. April 2005, 18:54

jens hat geschrieben: Ich habe dafür zwar eine Lösung, aber diese scheint mir nicht wirklich optimal:
Naja, einiges ginge schon einfacher.
Die größe eines dicts: len(data)
Liste mit den werten: filelist = data.values()
Um die schnittmenge aller listen zu ermitteln, gibt es die methode intersection() des datentyps set.
Vielleicht ein aktuelles buch kaufen :wink:
joe
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 24. April 2005, 19:08

joe hat geschrieben:Die größe eines dicts: len(data)
Liste mit den werten: filelist = data.values()
Danke, das hätte ich eigentlich wissen sollen :oops: (Ich werde es oben mal aktualisieren)
CM hat geschrieben:schau mal im Tutorial unter Sets. Bietet das alles was Du suchst?
Eigentlich schon... Aber es soll auch mit Python 2.2.1 gehen :cry:

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
joe

Sonntag 24. April 2005, 19:42

jens hat geschrieben:Aber es soll auch mit Python 2.2.1 gehen :cry:
Vielleicht alle werte in ein dict packen und dabei zählen:

Code: Alles auswählen

ll = [ [36, 37, 38, 39],[36, 37],[32, 33, 34, 35, 36, 37] ]
count = {}
for l in ll:
    for e in l:
        count[e] = count.get(e,0) + 1
        
res = [k for k,v in count.items() if v == len(ll)]
Geht aber nur, wenn in einer liste ein wert nur einmal vorkommt (was bei dateien eines verzeichnisses ja sichergestellt sein sollte).
joe
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 24. April 2005, 20:09

jens hat geschrieben:
CM hat geschrieben:schau mal im Tutorial unter Sets. Bietet das alles was Du suchst?
Eigentlich schon... Aber es soll auch mit Python 2.2.1 gehen :cry:
Ha! Man kann den Quellentext (./Lib/sets.py) auch in Python 2.2.1 benutzen :wink: Python ist ja sowas von cool :lol:

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 24. April 2005, 20:32

Wobei ganz zufrieden bin ich damit noch nicht:

Code: Alles auswählen

from sets import Set as set

def and_list( data ):
    filelist = data.values()

    if len( filelist ) == 1:
        # Es gibt nur eine, also sind alle Dateien treffer
        return filelist[0]

    print "Listen anzeigen:"
    for i in filelist: print i
    print "-"*80

    result = set( filelist[0] )
    for i in xrange( 1,len(filelist) ):
        result = result & set( filelist[i] )
    return list( result )


data = {
    "eins" : [36, 37, 38, 39],
    "zwei" : [36, 37],
    "drei" : [32, 33, 34, 35, 36, 37]
}

print "<pre>"
result = and_list( data )
print "Ergebnis:", result

print "-"*80

result = and_list( {"nureins":[1,2,3]} )
print "Ergebnis:", result

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Sonntag 24. April 2005, 21:20

Wieso kannst Du Sets importieren? "sets" steht doch gar nicht im globule module index von 2.2.1 - zumindest laut Doku ( http://www.python.org/doc/2.2.1/modindex.html ). Das verwirrt mich etwas.
Jedenfalls finde ich Deine Lösung nicht schlecht. Alternativ vielleicht noch folgende Lösung:

Code: Alles auswählen

def f(*args):
	for l in args[1:]: args[0].extend(l)
	l = []
	for x in args[0]:
		if x not in l and args[0].count(x) == len(args): l.append(x)
	return l
	
a = [1,2,3]
b = [3,2]
c = [6,5,4,3,2,1]

print f(a,b,c)
Gruß,
Christian
BlackJack

Sonntag 24. April 2005, 23:09

jens hat geschrieben:Wobei ganz zufrieden bin ich damit noch nicht:
Ich finde den Namen verwirrend. Ich fragte mich zuerst was `values()` sollte weil Listen diese Methode ja gar nicht haben.

Den Spezialfall in der ersten if-Abfrage kannst Du Dir sparen. Es sei denn das umwandeln Liste->Set->Liste ist wirklich zu langsam. Das Ergebnis ist jedenfalls das gleiche. Problematischer ist der Fall, wenn das Dictionary leer ist, dann gibts einen `IndexError`. Für den Fall ist im folgenden die Ausnahmebehandlung:

Code: Alles auswählen

def and_list( data ): 
    filelist_iter = iter(map(set, data.values()))
    # ``filelist_iter = imap(set, data.itervalues())`` in Python >= 2.3
    
    try:
        first = filelist_iter.next()
    except StopIteration:
        return list()
    
    return list(reduce(operator.and_, filelist_iter, first))
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 25. April 2005, 06:26

CM hat geschrieben:Wieso kannst Du Sets importieren? "sets" steht doch gar nicht im globule module index von 2.2.1 - zumindest laut Doku ( http://www.python.org/doc/2.2.1/modindex.html ).
OK, vielleicht hätte ich noch einen Satz dazu schreiben können. Ich habe die Datei ./Lib/sets.py von der Version 2.4 einfach zu meinem Skript gelegt. Durch den manuellen import mit "from sets import Set as set" steht es ganz normal zu verfügung...

Übrigends steht in sets.py ein Hinweis, der mich erst darauf gebracht hat:

Code: Alles auswählen

# Code to make the module run under Py2.2
@BlackJack: Du hast recht mit dem spezial Fall, mit nur einer Liste... Aber das Abfragen, wenn die Liste leer ist, kann ich mir in meinem Fall sparen. Das wird in meinem Programm schon vorher abgefangen...

Nun Frage ich mich, wie ich abfragen kann, ob es "set()" schon gibt oder nicht. Meine Variante:

Code: Alles auswählen

if not "set" in dir(__builtins__):
    from sets import Set as set

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 25. April 2005, 12:49

jens hat geschrieben:Nun Frage ich mich, wie ich abfragen kann, ob es "set()" schon gibt oder nicht. Meine Variante:

Code: Alles auswählen

if not "set" in dir(__builtins__):
    from sets import Set as set
Ich würds nach EAFP machen:

Code: Alles auswählen

try:
    set
except NameError:
    from sets import Set as set
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 25. April 2005, 13:27

Leonidas hat geschrieben:Ich würds nach EAFP machen
So geht's natürlich etwas weniger kompliziert... Ich find nur immer, das das so'n bischen Hammer-Methodik ist ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 25. April 2005, 13:33

jens hat geschrieben:So geht's natürlich etwas weniger kompliziert... Ich find nur immer, das das so'n bischen Hammer-Methodik ist ;)
Naja, so muss man nicht Python's __magische__ Variablen nutzen, außerdem ist das Verfahren ziemlich wasserdicht.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Dienstag 25. April 2006, 21:30

CM hat geschrieben: Jedenfalls finde ich Deine Lösung nicht schlecht. Alternativ vielleicht noch folgende Lösung:

Code: Alles auswählen

def f(*args):
	for l in args[1:]: args[0].extend(l)
	l = []
	for x in args[0]:
		if x not in l and args[0].count(x) == len(args): l.append(x)
	return l
	
a = [1,2,3]
b = [3,2]
c = [6,5,4,3,2,1]

print f(a,b,c)
Hallo,

zum einjährigen Jubiläum des Threads und weil ich mich gerade mit der Sache beschäftige, wollte ich meine Lösung, aufbauend auf CMs Vorschlag vorstellen:

Code: Alles auswählen

def f(*args):
	d, arg_num = {}, len(args)
	for l in args:
            for x in l:
                try:    d[x] += 1
                except: d[x]  = 1
	return filter(lambda x: arg_num == d[x], d.keys())
	
a = [1,2,3]
b = [3,2]
c = [6,5,4,3,2,1]

print f(a,b,c)
Wenn wir schon davon ausgehen, dass in den einzelnen Listen maximal ein Vorkommen existiert, kann man zum Zusammenfassen auch gleich ein Dict nehmen. Das geht schneller als die Verwendung von Listen und man braucht nicht immer die beiden Listen zu durchsuchen/-zählen, da der Vereinzellungseffekt beim Dict inklusive ist. Ansonsten ist das Prinzip wie bei CM, das kann man wohl nicht toppen. :-)

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Antworten