Loop - ohne doppelte Werte?

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
Quicktrader
User
Beiträge: 16
Registriert: Freitag 6. November 2015, 20:24

Hallo..

um mehrere verschachtelte ('nested') FOR loops miteinander zu kombinieren, gibt es eine feine Lösung:

Code: Alles auswählen

LIST_1 = ['a', 'b']
LIST_2 = ['b', 'c']
for x, y in [(x,y) for x in LIST_1 for y in LIST_2]:
   print(x+y)
Das Resultat dürfte so aussehen:

ab
ac
bb
bc

Soweit so gut. Allerdings habe ich das Thema, dass wenn zwei Werte in den Listen GLEICH sind, diese nicht aufscheinen, am besten gar nicht berücksichtigt werden sollen ('bb'). Wenn x = 'b' ist, soll also y als Wert 'b' gar nicht erst zur Verwendung kommen (noch vor dem Print-Befehl, also noch im Loop).

Ziel ist, die Optimierung des Rechenaufwands, ein 'nachträgliches' Löschen von 'bb' oder dergleichen kommt also leider nicht in Frage. Die Listen LIST_1 bzw. LIST_2 sind überdies vorgegeben.

Setze ich eine entsprechende Regel VOR dem Loop, so erscheint während dem Loop selbst ein 'Syntax error' (da Python ja die Aufgabe hat 'b' mit 'b' zu kombinieren, dies jedoch nicht 'darf' - der Loop führt somit, wenn ich nicht irre, zur Fehlermeldung).

Meine Frage ist daher, ob es eine Möglichkeit gibt, die wie oben dargestellte Kombination der beiden Loops über LIST_1 und LIST_2 so zu modifizieren, dass gleiche Werte erst gar nicht (simultan) für die (hier) weitere Print-Bearbeitung selektiert werden?

Das Ergebnis sollte dann also, aus der Iteration heraus wurzelnd, so aussehen:

ab
ac
bc

Danke für jegliche Ideen,

QT
Zuletzt geändert von Quicktrader am Sonntag 18. November 2018, 20:37, insgesamt 2-mal geändert.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich verstehe nicht, wie Du eine entsprechende Regel VOR dem Loop programmiert haben willst?

Die einfache Lösung ist es, x mit y zu vergleichen.

Code: Alles auswählen

LIST_1 = ['a', 'b', 'c']
LIST_2 = ['c', 'd', 'e']
pairs = ((x,y) for x in LIST_1 for y in LIST_2 if x != y)
for x, y in pairs:
   print(x+y)
Quicktrader
User
Beiträge: 16
Registriert: Freitag 6. November 2015, 20:24

Das scheint die richtige Lösung zu sein, besten Dank (mit FOR funktioniert der Zusatz 'a != b' nicht)

QT
Quicktrader
User
Beiträge: 16
Registriert: Freitag 6. November 2015, 20:24

Hallo...

der Hinweis mit 'pairs' hat sehr geholfen. Allerdings bin ich noch immer zu 'verschachtelt'. Programm schaut in etwa so aus und macht im Prinzip was man davon erwartet (Pseudo-Pyhton):

Code: Alles auswählen

vowels = ['A', 'E', 'I', 'O', 'U']
consonants = ['B', 'C', 'D',...'Y', 'Z']

#loop1
pairs1 = ((A,B) for A in vowels for B in consonants)
for A,B in pairs1:
       string1 = TEXT1
       if "AB" in string1:

               #loop2
               pairs2 = ((C,D) for C in consonants for D in vowels)
               for C,D in pairs2:
                     string2 = TEXT2
                     if "BBCD" in string2:
                          
                          #loop3
                          pairs3 = ((E,F) for E in vowels for F in consonants)
                          .....
Also im Prinzip drei ineinander verschachtelte FOR-Loops, was natürlich für die Performance nicht sonderlich gut ist. Allerdings soll #loop2 wirklich nur dann berechnet werden, wenn in #loop1 zuvor "AB" im Text TEXT1 gefunden wurde (sprich alle Variablen, d.h. auch C + D mit A + B zusammenzufassen macht keinen Sinn, da ja "AB" noch nicht im TEXT1 gefunden wurde. Jeder Loop ist überdies etwas anders gestaltet, z.B. zwei oder drei Variablen, anderer Text in dem gesucht wird. Auch sind die nachfolgenden Loops von den vorhergehenden 'abhängig'.

Dennoch wäre es 'schön', wenn man die Vorgehensweise, die ja vom Prinzip her bei allen drei Loops gleich ist, zusammenfassen könnte (z.B. eine Funktion?). Einfach um die mehrfache Verschachtelung zu umgehen? Derzeit habe ich ca. 5-6 solcher Loops ineinander verschachtelt und denke mir, da könnte es einen 'Workaround um the Bottleneck' geben...?

Danke + lg aus Budapest

QT-Newbie
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn es um Performance geht, dann ist das itertools-Modul oft hilfreich:

Code: Alles auswählen

from itertools import product, starmap
from operator import add

result = starmap(add, product('ab', 'bc'))
print('\n'.join(result))
Die tatsächliche Berechnung findet erst beim join() statt. Man kann also Berechnungen vorbereiten, sofern die Werte feststehen und sie bei Bedarf durchführen. Natürlich muss es nicht zwingend join() sein. Eine for-Schleife über result ginge genau so. Wie bei einem Generator-Ausdruck sind die Elemente dann aber auch aufgebraucht und können nicht wiederholt durchlaufen werden.
Zuletzt geändert von snafu am Montag 10. Dezember 2018, 15:19, insgesamt 1-mal geändert.
Quicktrader
User
Beiträge: 16
Registriert: Freitag 6. November 2015, 20:24

Danke für den Hinweis, werde ich ausprobieren.

QT
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Da ja gleiche Paare herausgefiltert werden sollen:

Code: Alles auswählen

from itertools import compress, product, starmap, tee
from operator import ne

pairs, pairs2 = tee(product('ab', 'bc'))
non_equal = compress(pairs, starmap(ne, pairs2))
for pair in non_equal:
    print(pair)
Das erzeugt die Paare nun ohne explizite Schleife und ohne dazwischengeschaltete Listen, wirkt aber auch etwas umständlich.

Wahrscheinlich würde ich wohl eher eine Mischform nehmen:

Code: Alles auswählen

pairs = ((x, y) for x, y in product('ab', 'bc') if x != y)
#print(list(pairs))
Wurde ja auch in ähnlicher Form bereits gezeigt.

Der dritte Weg wäre dann noch filter() in Kombination mit lambda, da man ne() dafür nicht direkt nutzen kann. Erfahrungsgemäß macht man sich aber mit Lambda-Funktionen (bzw Funktionen mit Python-Code im Allgemeinen) den Geschwindigkeitsvorteil wieder kaputt. Und dann kann man es halt auch gleich als Generator ausschreiben. Du kannst ja mal ein paar Messungen machen (Stichwort: timeit) und schauen wie du vorgehen möchtest.
Antworten