Liste enthält ALLE Werte einer anderen Liste -reg. Ausdrücke

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
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Hallo,

ich möchte gerne überprüfen, ob ALLE Werte einer Liste in einer anderen Liste vorhanden sind. Solange es sich um einfache Werte handelt, ist das kein Problem - bei der Überprüfung habe ich die Listen in Sets umgewandelt und führe den Test mit "issubset" durch. Das funktioniert auch soweit.
Nun kann es aber sein, dass auch reguläre Ausdrücke zur Überprüfung anstehen - also, das Prg soll schauen, ob ALLE Werte (auch reg. Ausdrücke) in der anderen Liste vorkommen. Die regulären Ausdrücke sollen natürlich angewendet werden.

Als Script sieht es zur Zeit in etwa so aus:

Code: Alles auswählen

ProjectList = [['D', '1', 'fumm0134', 'test', '/tmp/software/bin', 'PRD'], ['D', '1', 'fumm0071', 'test', '/tmp/software/bin', 'UAT']]
PatternList1 = ['fumm0134', 'PRD']
PatternList2 = ['134$', 'PRD']

NewList1 = []
for row in ProjectList:
  if set(PatternList1).issubset(set(row)):
    NewList1.append(row)

NewList2 = []
for row in ProjectList:
  if set(PatternList2).issubset(set(row)):
    NewList2.append(row)

print NewList1
print NewList2
Die Ausgabe wäre dann:
[['D', '1', 'fumm0134', 'test', '/tmp/software/bin', 'PRD']]
[]
Der 1. Fall funktioniert ja (PatternList1).
Der 2. Fall enthält als 1. Wert einen reg. Ausdruck (PatternList2).

Ziel wäre hier die gleiche Ausgabe in beiden Fällen!

Muss ich in diesem Fall verschachtelte Schleifen verwenden? Oder weiss jemand hier was besseres?

CU,
API
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sehe ich das richtig, dass Unterlisten immer komplett übernommen werden, sobald ein Kriterium aus der Pattern-Liste passt?

Wie tief verschachtelt kann es denn noch werden? Sind es immer Listen in einer Liste? Oder kann es da noch tiefer / höher gehen? Also Listen in Listen, Elemente auf oberster Ebene? Und wenn ja, wie wird dann die Übernahme geregelt?

Wenn Du auf RegExps testen willst, kannst Du den Weg über sets natürlich vergessen. Du musst eben für jedes Element der pattern-Liste alle Elemente der jeweiligen Prüfliste durchgehen und gucken, ob der re matcht. Sobald der erste gematcht hat, kannst Du den ja abbrechen und mit dem nächsten Ausdruck weiter machen.

Edit: So könnte ich es mir vorstellen. Das ganze musst Du dann eben noch entsprechend auswerten und die passenden Zeilen in Deine Ergebnisliste packen:

Code: Alles auswählen

In [81]: patterns = [r".*134$", r"PRD"]

In [82]: projects = [['D', '1', 'fumm0134', 'test', '/tmp/software/bin', 'PRD'],
 ['D', '1', 'fumm0071', 'test', '/tmp/software/bin', 'UAT']]

In [83]: [all(any(imap(partial(re.match, pattern), row)) for pattern in patterns) for row in projects]
Out[83]: [True, False]
Könnte man mit itertools.compress realisieren. Wohl gemerkt gehe ich davon aus, dass es sich immer um Listen in einer Oberliste handelt.

Ach so, partial stammt aus dem functool-, imap aus dem itertools-Modul.
Zuletzt geändert von Hyperion am Mittwoch 26. Januar 2011, 18:12, insgesamt 2-mal geändert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@Hyperion:
Sehe ich das richtig, dass Unterlisten immer komplett übernommen werden, sobald ein Kriterium aus der Pattern-Liste passt?
Es müssen immer ALLE Kriterien einer Pattern-Liste passen.
Wie tief verschachtelt kann es denn noch werden? Sind es immer Listen in einer Liste? Oder kann es da noch tiefer / höher gehen? Also Listen in Listen, Elemente auf oberster Ebene? Und wenn ja, wie wird dann die Übernahme geregelt?
So wie die Liste im Beispiel angegeben ist - tiefer geht es nicht. Also 2 Dimensionen.
Wenn Du auf RegExps testen willst, kannst Du den Weg über sets natürlich vergessen. Du musst eben für jedes Element der pattern-Liste alle Elemente der jeweiligen Prüfliste durchgehen und gucken, ob der re matcht. Sobald der erste gematcht hat, kannst Du den ja abbrechen und mit dem nächsten Ausdruck weiter machen.
Wenn du damit die PatternList meist, ja - ich könnte nach dem 1. Treffer mit dem nächsten Ausdruck weitermachen...
Das läuft dann also doch auf verschachtelte Schleifen hin, oder?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hier mit Rausfiltern der passenden Projektlisten:

Code: Alles auswählen

In [99]: list(compress(projects, (all(any(imap(partial(re.match, pattern), row)) for pattern in patterns) for row in projects)))
Out[99]: [['D', '1', 'fumm0134', 'test', '/tmp/software/bin', 'PRD']]
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Erstmal Danke für die schnelle Antwort.

Allerdings verstehe ich den Code nicht wirklich... :?

Ich werd das wohl mal nachschlagen müssen - kannst du mir aber mal nen Hinweis darauf geben, wo ich das Kommando "imap" finde?
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@Hyperion:

Ich habe 2 Python-Versionen zur Auswahl: 2.4.6 oder 3.1.2

In 3.1.2 meckert er immer das imap an - inzwischen weiss ich, dass es zu itertools gehört...
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

api hat geschrieben: In 3.1.2 meckert er immer das imap an - inzwischen weiss ich, dass es zu itertools gehört...
In Python >= 3.x gibt es kein imap mehr, da das late"map" aus den Standard-Funktionen aus 2.x nun einen Iterator liefert und keine Liste mehr. Sprich, das alte imap ist das neue map. imap gibts nicht mehr in 3.x

Der Code sieht komplizierter aus, als er ist. Man muss sich da nur ein wenig reindenken und von "innen nach außen" lesen.

Im inneren führe ich ein re.match mit einem pattern durch das (i)map gegen alle Elemente einer Reihe aus. Das partial ist notwendig, da re.match zwei Parameter verlangt, man bei map aber nur einen übergeben darf. Matcht der Ausdruck mindestens einmal, so liefert das any() ein True. Nun muss das für alle pattern einer pattern-Liste ja gelten, weswegen das all zum Tragen kommt in einem Generatorausdruck, in dem ich über die pattern iteriere. Da drum herum gehe ich einfach wieder per Generatorausdruck über alle rows aus der Projektliste. Ganz drum herum nutze ich compress, welches nur die Elemente eines Iterable zurückliefert, bei denen ein korrespondierendes Objekt True ist.
Zuletzt geändert von Hyperion am Mittwoch 26. Januar 2011, 19:36, insgesamt 1-mal geändert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@Hyperion:

Ich habe jetzt folgendes versucht:

Code: Alles auswählen

for row in ProjectList:
  NewList2 = list(compress(ProjectList, (all(any(map(partial(re.match, pattern), row)) for pattern in PatternList4) for row in ProjectList)))

print (NewList2)
Und was soll ich sagen, es funzt !!! Verwendet habe ich nun Python 3.1.2 - weil das compress erst ab 2.7 verfügbar ist...

Ich danke dir :D (Wenn ich mir den Code auch nochmal näher ansehen muss... :wink: )
Antworten