Voor geneste lussen vermijden

Ik probeer parameter-testen uit te voeren op een andere code met behulp van python. Ik moet 6 onafhankelijke parameters testen, maar ik heb alle mogelijke combinaties ervan nodig.

Elke parameter heeft een minimum, een maximum en een stapwaarde die eraan moet worden doorgegeven. De eerste eenvoudige oplossing die in mijn hoofd opkwam, was een genestelde lusstructuur die er afschuwelijk uitzag, zoals deze:

for var1 in xrange(min1,max1,step1):
    for var2 in xrange(min2,max2,step2):
        ...
            ...
                ...
                    for var6 in xrange(min6,max6,step6):
                        '''
                        Do something and be icky in the process due
                        to being in the middle of six nested for loops
                        '''

Ik besloot, nee! Dit zal niet blijven staan. Dus ik heb geprobeerd een manier uit te werken om dit recursief te doen, of op zijn minst zes keer niet te genest. Ik kan niet echt een goed plan bedenken om dit te doen. Het grootste obstakel voor mij is dat elke variabele een andere min-, max- en stapwaarde heeft.

Mijn gedachten tot nu toe zijn niet erg behulpzaam. Ik blijf proberen om een ​​recursieve functie te laten werken, maar ik kan er gewoon niet achter komen zonder meer te nestelen voor loops binnen de functie. Ik heb hier heel wat verwijzingen gezien naar itertools.product, maar ik kan er niet helemaal achter komen hoe ik dat werk kan maken.

Bewerken: Wat ik aan het doen ben is een map aan te maken die genoemd is naar de combinatie van de parameters, een bestand met die parameters schrijft, een andere code uitvoert met dit bestand en de uitvoer van die code analyseert. Ik doe niets in letterlijk één van de for-loops, behalve de laatste. Veel van de parameters hebben slechts twee waarden, sommige hebben er 10, andere hebben er 3 ... het varieert nogal.

21
@deathApril heeft gelijk: ik heb je een manier gegeven om de onderstaande lussen te vermijden, maar je moet nog steeds al die iteraties doen. Het zou beter zijn om een ​​ander algoritme te gebruiken om de iteraties te vermijden.
toegevoegd de auteur Ned Batchelder, de bron
@deathApril: u bent de enige die spreekt over prestaties. Het OP noemde helemaal niets, dit gaat niet over prestaties, maar over de structuur van de code.
toegevoegd de auteur Ned Batchelder, de bron
@ user1477556: maak je geen zorgen, je intuïties kloppen. Ik gebruik itertools.product altijd voor precies dit doel, eenvoudige constructie van parameterrasters, meestal met behulp van de tuple-uitpakkende aanpak (met * op lijsten) beschreven door Ned Batchelder, en het is de juiste manier.
toegevoegd de auteur DSM, de bron
Het punt gaat niet over het gebruiken of niet gebruiken van lussen; het is meer dat je misschien niet begrijpt hoe snel het aantal testgevallen toeneemt. 6 instellingen, elk met 10 mogelijke waarden, is een miljoen testgevallen.
toegevoegd de auteur Hugh Bothwell, de bron
wat moet er eigenlijk in al die loops worden gedaan? ik denk dat dit de belangrijkste vraag is - er zijn wat syntaxisuikers om de lussen te verbergen (maar nog steeds te maken), maar om geneste loops te vermijden, is het belangrijkste om het oorspronkelijke probleem te onderdrukken
toegevoegd de auteur Aprillion, de bron
@ user1477556 eh , je wilt alleen maar zeggen dat je ons voor slechts een paar microseconden lastigvalt - of wat was slecht aan de originele for loops?
toegevoegd de auteur Aprillion, de bron
ik zie dat het itertools.product je probleem heeft opgelost. goed voor je. wees niet verbaasd wanneer je ontdekt dat het prestatieverschil tussen expliciete geneste for-lussen en verborgen C-code die geneste lussen uitvoert, alleen maar zo groot kan zijn;) PS: eigenlijk zou het leuk zijn als je de resultaten van de prestatietests hebt gepost: ))
toegevoegd de auteur Aprillion, de bron
Een bewerking toegevoegd om uit te leggen waarom ik dit nodig heb
toegevoegd de auteur rapidsnow, de bron
@deathApril wat? Ik probeer niet onbeleefd te zijn, ik begrijp gewoon je laatste opmerking niet. Er was niets inherent slecht aan hen anders dan dat de gebruikelijke codeermethode is om te voorkomen dat er meer dan 2-3 lussen worden genest. Ik moet alle mogelijke combinaties doorlopen. Als je een manier zou kunnen bedenken om alles door te lussen zonder te nestelen voor lussen (behalve syntactische suiker), zou ik het graag horen. Ik ben een beetje nieuw bij het coderen en elk advies wordt op prijs gesteld.
toegevoegd de auteur rapidsnow, de bron

2 antwoord

Zo gebruikt u product :

x1 = xrange(min1,max1,step1)
x2 = xrange(min2,max2,step2)
x3 = xrange(min3,max3,step3)
...

for v1, v2, v3, v4, v5, v6 in itertools.product(x1, x2, x3, x4, x5, x6):
    icky_thing(....)

of een beetje compacter:

ranges = [
    xrange(min1,max1,step1),
    xrange(min2,max2,step2),
    xrange(min3,max3,step3),
    ...
]

for v1, v2, v3, v4, v5, v6 in itertools.product(*ranges):
    icky_thing(....)
38
toegevoegd
mooie code <3
toegevoegd de auteur gabeio, de bron
Leuk! Was op het punt om een ​​vraag te stellen over hoe dit te doen!
toegevoegd de auteur madbitloman, de bron

U kunt waarschijnlijk itertools.product gebruiken: http://docs.python.org /library/itertools.html#itertools.product .

Zoiets als

for var1, var2 in itertools.product(xrange(min1, max1, step1), xrange(min2, max2, step2)):
    # stuff

. . . alleen met alle zes vars erin.

14
toegevoegd