Seite 1 von 1

variable anzahl an verschachtelten for-schleifen

Verfasst: Sonntag 6. Mai 2007, 22:36
von netzmensch
hi,

ich möchte eine variable zahl an for-schleifen ineinander verschachteln, komme aber einfach nicht auf die passende idee das zu realisieren

das meine ich:

Code: Alles auswählen


test = ["a","b","c"]
test2 = ["1","2","3"]
test3 = ["x","y","z"]

for a in test:
   for b in test2:
      for c in test3:
          .....
nun will ich es möglich machen, das ich z.b. (durch auswahl des users) nur die ersten beiden for schleifen nutze, oder halt alle drei, oder mehr...

der netzmensch

Verfasst: Montag 7. Mai 2007, 02:03
von joost
Verstehe ich Dein Problem mit folgendem Code richtig ?

Code: Alles auswählen

test = ["a","b","c"]
test2 = ["1","2","3"]
test3 = ["x","y","z"]

for a in test:
    if user=='aNotAllowed': break    
    for b in test2:
        if user=='bNotAllowed': break
        for c in test3:
usw.

Wenn die Erlaubnis 'springen' können soll, dann vielleicht so:

Code: Alles auswählen

test = ["a","b","c"]
test2 = ["1","2","3"]
test3 = ["x","y","z"]

for a in test:
    for b in test2:
        if user=='bMustBe2' and b!=2: continue 
        for c in test3:
Noch weitergehend könnte man Listen für User aufbauen, mit je einem Eintrag pro 'for'.

Vorschlag

Verfasst: Montag 7. Mai 2007, 06:55
von sunmountain
Wenn Du Deine Listen in einem dict organisieren würdest,
könntest Du geziehlt welche auswählen.
Das dynamische Schachteln halte ich im Moment nur für möglich,
wenn man sich das dazugehörige Codestück dynamisch zusammenbaut
und anschliessend mit eval/exec ausführt.

Code: Alles auswählen


lists = {'test1':[1,2,3,4],'test2':[1,2,3,4],'test3':[1,2,3,4]} # die Listen
order = ('test3','test1','test2') # Die Schachtelung
forbidden = () # Alle sollen laufen
snippet = ''

def ident(n):
    return '    '*n

for n,o in enumerate([o for o in order if o not in forbidden]):
    snippet += ident(n) + '%s = %s' % (o,repr(lists[o])) + '\n'
    snippet += ident(n) + 'for a%i in %s:'  % (n,o) + '\n'
    snippet += ident(n+1) + 'print "%s",a%i' % (o,n) + '\n'

print snippet
exec(snippet)

Ergebnis:

Code: Alles auswählen

test3 = [1, 2, 3, 4]
for a0 in test3:
    print "test3",a0
    test1 = [1, 2, 3, 4]
    for a1 in test1:
        print "test1",a1
        test2 = [1, 2, 3, 4]
        for a2 in test2:
            print "test2",a2

test3 1
test1 1
test2 1
test2 2
test2 3
test2 4
test1 2
test2 1
test2 2
test2 3
test2 4
test1 3
test2 1
test2 2
test2 3
test2 4
test1 4
test2 1
test2 2
test2 3
test2 4
test3 2
test1 1
test2 1
test2 2
test2 3
test2 4
test1 2
test2 1
test2 2
test2 3
test2 4
test1 3
test2 1
test2 2
test2 3
test2 4
test1 4
test2 1
test2 2
test2 3
test2 4
test3 3
test1 1
test2 1
test2 2
test2 3
test2 4
test1 2
test2 1
test2 2
test2 3
test2 4
test1 3
test2 1
test2 2
test2 3
test2 4
test1 4
test2 1
test2 2
test2 3
test2 4
test3 4
test1 1
test2 1
test2 2
test2 3
test2 4
test1 2
test2 1
test2 2
test2 3
test2 4
test1 3
test2 1
test2 2
test2 3
test2 4
test1 4
test2 1
test2 2
test2 3
test2 4

Re: Vorschlag

Verfasst: Montag 7. Mai 2007, 08:11
von EyDu
Rekursion ist das Stichwort.

Verfasst: Montag 7. Mai 2007, 08:28
von joost
Ach, ich merke gerade: In meinem zweiten Beispiel sollte es auch besser 'break' statt 'continue' heißen.

Und eine Rekursion kann man machen, zusammen mit einem dict wie

PermissionDict['aNotAllowed'] = (1,0,0,0,0 ...)
PermissionDict['cNotAllowed'] = (1,1,0,0,0, ...)
PermissionDict['aAndcAllowed] = (1,0,1,0,0,..)

- man wird aber wohl doch immer eine feste Tiefe der for-Schachtelung haben (vielleicht auch wegen der - wahrscheinlich ja konstanten - Start-Listen). Dann wäre Rekursion mir persönlich zu teuer.

Re: Vorschlag

Verfasst: Montag 7. Mai 2007, 12:02
von netzmensch
also der tip von sunmountain trifft es am besten...hab mich schon ne weile gefragt wozu das exec eigentlich gut ist...nun weiß ich es. danke!

Verfasst: Montag 7. Mai 2007, 12:51
von BlackJack
Stilistisch ist der Tip nicht so gut. Rekursion wäre die sauberere Lösung. Wenn man in einer dynamischen Sprache auf Code-Generierung zurück greift, macht man im allgemeinen etwas falsch. Und in diesem Falle wäre das nicht einmal in einer statischen Sprache nötig.

Verfasst: Montag 7. Mai 2007, 15:16
von netzmensch
rekursiv habe ich mir auch schon überlegt, aber ich komme nicht drauf wie ich das realisieren kann...

meine idee dazu war folgendes:

Code: Alles auswählen

def schleife(anzahl_schleifen, array):
     for i in anzahl_schleifen:
        for b in array:
            schleife(?hier weiß ich nicht was rein soll?, array)
            

test1 = ["a","b","c"]

schleife(3,test1)

problem dabei ist nun, das ich nicht drauf komme die anzahl bei der rekursion richtig zu wählen, und ausserdem weiß ich nicht wie ich mir nacheinander alle state's der schleifen pro durchlauf returnen lassen kann.
ich möchte quasi alle möglichen kombinationen der schleifen zurückgegeben haben.

Verfasst: Montag 7. Mai 2007, 16:39
von BlackJack
Hier ist eine iterative Lösung bei der sowohl die Anzahl der Listen als auch deren Längen flexibel sind:

Code: Alles auswählen

from itertools import imap
from operator import mul


def combinations(iterable):
    sequences = list(reversed(iterable))
    max_value = reduce(mul, imap(len, sequences))
    for value in xrange(max_value):
        result = list()
        for sequence in sequences:
            value, index = divmod(value, len(sequence))
            result.append(sequence[index])
        result.reverse()
        yield result


def main():
    test1 = ['a','b','c']
    test2 = ['1','2','3']
    test3 = ['x','y','z']
    
    for a in test1:
        for b in test2:
            for c in test3:
                print [a, b, c]
    
    for combination in combinations((test1, test2, test3)):
        print combination
Die beiden Schleifen geben das gleiche aus.

Edit: In `combinations()` die `lengths`-Liste entfernt und damit die innere Schleife etwas lesbarer gemacht.

Verfasst: Montag 7. Mai 2007, 16:57
von joost
Hübsch ! :)