开发者

Function with varying number of For Loops (python) [duplicate]

This question already has answers here: Avoiding nested for loops (3 answers) Closed 27 days ago.

My problem is difficult to explain.

I want to create a function that contains nested for loops,

the amount of which is proportional to an argument passed to the function.

Here's a hypothetical example:

Function(2)

...would involve...

for x in range (y):
    for x in range (y):
        do_whatever()

Another example...

  Function(6)

...would involve...

for x in range (y):
    for x in range (y):
        for x in range (y):
            for x in range (y):
                for x in range (y):
                    for x in range (y):
                        whatever()

The variables of the for loop (y) are NOT actually used in the nested code.

Your first thought might be to create ONE for loop, with a range that is to the power of the number argument...

THIS CAN NOT WORK because the product would be HUGE. I have instances required where there are 8 nested for loops.

The product is too large for a range in a for loop.

There are other arguments needed to be passed to the function, but I can handle that myself.

Here's the code (it creates the Snowflake Fractal)

from turtle import *
length = 800
speed(0)

def Mini(length):
    for x in range (3):
        forward(length)
        right(60)

penup()
setpos(-500, 0)
pendown()   

choice = input("Enter Complexity:")

if choice == 1:
    for x in range (3):
        forward(length)
        left(120)

elif choice == 2:
    for x in range (3):
        Mini(length/3)
        left(120)

if choice == 3:
    for x in range (6):
        Mini(length/9)
        right(60)
        Mini(length/9)
        left(120)

if choice == 4:
    for y in range (6):
        for x in range (2):
            Mini(length/27)
            right(60)
            Mini(length/27)
            left(120)
        right(180)
        for x in range (2):
            Mini(length/27)
            right(60)
            Mini(length/27)
            left(120)

if choice == 5:
    for a in range (6):
        for z in range (2):
            for y in range (2):
                for x in range (2):
                    Mini(length/81)
                    right(60)
                    Mini(length/81)
                    left(120)
                right(180)
                for x in range (2):
                    Mini(length/81)
                    right(60)
                    Mini(length/81)
                    left(120)
            right(180)
        right(180)

if choice == 6:
    for c in range (6):
        for b in range (2):
            for a in range (2):
                for z in range (2):
                    for y in range (2):
                        for x in range (2):
                            Mini(length/243)
                            right(60)
                            Mini(length/243)
                            left(120)
                        right(180)
                        for x in range (2):
                            Mini(length/243)
                            right(60)
                            Mini(length/243)
                            left(120)
                    right(180)
                right(180)
            right(180)
        right(180)

if choice == 7:
    for a in range (6):
        for b in range(2):
            for c in range (2):
                for d in range (2):
                    for e in range (2):
                        for f in range (2):
                            for y in range (2):
                                for x in range (2):
                                    Mini(length/729)开发者_运维知识库
                                    right(60)
                                    Mini(length/729)
                                    left(120)
                                right(180)
                                for x in range (2):
                                    Mini(length/729)
                                    right(60)
                                    Mini(length/729)
                                    left(120)
                            right(180)
                        right(180)
                    right(180)
                right(180)
            right(180)
        right(180)

I'd appreciate any help you can give me at all,

though if you suggest a different method (such as recursion),

please don't just paste the code; instead, suggests some ideas that could put me in the right direction.

(The algorithm is for a Specialist Math Assignment)


specs:

Python 2.7.1

Turtle

IDLE

Windows7


I'm not clear why you can't use the product of the bounds and do

for x in range(y exp n)

where n is the # of loops.... You say y exp n will be huge, but I'm sure python can handle it.

However, that being said, what about some sort of recursive algorithm?

def loop_rec(y, n):
    if n >= 1:
        for x in range(y):
            loop_rec(y, n - 1)
    else:
       whatever()


This problem can be solved by recursion. I am just writing an algorithm here, since I believe this can be a general problem.

function Recurse (y, number) 
   if (number > 1)
      Recurse ( y, number - 1 )
   else
      for x in range (y)
          whatever()


Recursion will be your best bet. Consider what it should do in the base case and in the recursive case.

Code left out, as per request.


Here you go. Let ranges be your ranges, operate on result when you need to.

ranges=((1,4),(0,3),(3,6))
from operator import mul
operations=reduce(mul,(p[1]-p[0] for p in ranges))-1
result=[i[0] for i in ranges]
pos=len(ranges)-1
increments=0
print result
while increments < operations:
    if result[pos]==ranges[pos][1]-1:
        result[pos]=ranges[pos][0]
        pos-=1
    else:
        result[pos]+=1
        increments+=1
        pos=len(ranges)-1 #increment the innermost loop
        print result

[1, 0, 3]
[1, 0, 4]
[1, 0, 5]
[1, 1, 3]
[1, 1, 4]
[1, 1, 5]
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[2, 0, 3]
[2, 0, 4]
[2, 0, 5]
[2, 1, 3]
[2, 1, 4]
[2, 1, 5]
[2, 2, 3]
[2, 2, 4]
[2, 2, 5]
[3, 0, 3]
[3, 0, 4]
[3, 0, 5]
[3, 1, 3]
[3, 1, 4]
[3, 1, 5]
[3, 2, 3]
[3, 2, 4]
[3, 2, 5]
[1, 0, 4]

Testing with the following would give the same result:

for x in range(*ranges[0]):
    for y in range(*ranges[1]):
        for z in range(*ranges[2]):
            print [x,y,z]


A nice implementation of the varying number of For Loops problem:

def for_recursive(number_of_loops, range_list, execute_function, current_index=0, iter_list = []):

if iter_list == []:
    iter_list = [0]*number_of_loops

if current_index == number_of_loops-1:
    for iter_list[current_index] in range_list[current_index]:
        execute_function(iter_list)
else:
    for iter_list[current_index] in range_list[current_index]:
        for_recursive(number_of_loops, iter_list = iter_list, range_list = range_list,  current_index = current_index+1, execute_function = execute_function) 

An example of how to use it:

def do_whatever(index_list):
    return print(index_list)


for_recursive(range_list = [range(0,3), range(0,3) , range(1,3)], execute_function = do_whatever , number_of_loops=3)

The code returns the same that this code:

for i in range(0,3):
    for j in range(0,3):
        for k in range(1,3):
            print([i,j,k])


Have you considered xrange ?

for x in xrange(y ** n):
    whatever()

And if you overshoot even xrange limit, you can use itertool

import itertools
for x in itertools.product(xrange(y), repeat=n):
   whatever()

(previous itertool answer incorrectly used n for the range instead of y)


Here is another option for iterative solution, seems simpler to me. The idea is to use an analogy with a 10 or X-based numbering system. Where you basically increase your number/count by one each time but the representation changes according to the base. I.e. if the base is 10, then the number changes 1 .. 9 10 11 .. 19 20... Imagine that we want to loop on i,j,k from 0 .. 9 for each. We run the loop for counter in range(101010) and take the digits as the values of the number. E.g. 731 means i=7,j=3, k=1. To make the case more general, where the range for each i/j/... is different - we take modulo that range:

`

ranges = [2,3,4]
lenr = len(ranges)
for i in range(2*3*4):
    perm = []
    d, r  = i, 0
    for rng_i in (1, lenr):
        d, r = divmod(d, ranges[lenr - rng_i])
        perm.append(r)
    perm.extend([0]*(lenr-len(perm)))   # pad with zeros
    print (list(reversed(perm)))        # need to reverse as appended from right

Output will be:

[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 1, 3]
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 1, 3]
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 1, 3]

`


My reply is late, but supposing that you want to do multiple loops, e.g. print some range multiple times. Then the correct version of this recursion is:

def loop_rec(y, number):
   if (number > 1):
      loop_rec( y, number - 1 )
      for i in range(y): 
         print(i, end=' ')        
   else:      
      for i in range(y):
         print(i, end=' ')

loop_rec(4,3)

This will create three for loops with the range(4)

If you want to play around with dynamic range, here are some variants:

def loop_rec(y, number):
if (number > 1):
    loop_rec( y+1, number - 1 )
    for i in range(y): 
        print(i, end=' ')
    print(' ;')
else:      
    for i in range(y):
        print(i, end=' ')
    print(';')

loop_rec(6,4)

which will print out:

0 1 2 3 4 5 6 7 8 ;
0 1 2 3 4 5 6 7  ;
0 1 2 3 4 5 6  ;
0 1 2 3 4 5  ;

or

def loop_rec(y, number):
if (number > 1):
    loop_rec( y-1, number - 1 )
    for i in range(y): 
        print(i, end=' ')
    print(' ;')
else:      
    for i in range(y):
        print(i, end=' ')
    print(';')
loop_rec(6,4)

which will output:

0 1 2 ;
0 1 2 3  ;
0 1 2 3 4  ;
0 1 2 3 4 5  ;

A better variant which is using only one for loop (less typing) is the following:

def loop_rec(y, number):
    if (number >= 1):
        loop_rec( y+1, number - 1 )
        for i in range(y): 
            print(i, end=' ')
        print('')
    else:      
        return

loop_rec(1,5)

will output:

0 1 2 3 4 
0 1 2 3 
0 1 2 
0 1 
0 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜