Функция с различным количеством циклов For Loops (python)

Мою проблему трудно объяснить.

Я хочу создать функцию, содержащую вложенные циклы for,
количество которых пропорционально аргументу, переданному функции.

Вот гипотетический пример:

Function(2)

...будет включать...

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

Другой пример...

  Function(6)

...будет включать...

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()

Переменные цикла for (y) фактически НЕ используются во вложенном коде.

Ваша первая мысль может состоять в том, чтобы создать ОДИН цикл for с диапазоном, равным степени числового аргумента...
ЭТО НЕ МОЖЕТ РАБОТАТЬ, потому что результат будет ОГРОМНЫМ. У меня есть требуемые экземпляры с 8 вложенными циклами for.
Произведение слишком велико для диапазона в цикле for.

Есть и другие аргументы, которые необходимо передать функции, но я могу справиться с этим сам.

Вот код (он создает фрактал снежинки)

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)

Я был бы признателен за любую помощь, которую вы можете мне оказать,
хотя, если вы предлагаете другой метод (например, рекурсию),
пожалуйста, не просто вставляйте код; вместо этого предлагает некоторые идеи, которые могли бы направить меня в правильном направлении.

(Алгоритм предназначен для задания специалиста по математике)


спецификации:
Python 2.7.1
Turtle
IDLE
Windows7


person Anti Earth    schedule 25.08.2011    source источник
comment
Есть ли что-то в использовании рекурсии для этого, чего вы не понимаете?   -  person outis    schedule 25.08.2011
comment
Если вас беспокоит размер range, просто используйте xrange.   -  person Keith    schedule 25.08.2011


Ответы (8)


Эту проблему можно решить с помощью рекурсии. Я просто пишу здесь алгоритм, так как считаю, что это может быть общей проблемой.

function Recurse (y, number) 
   if (number > 1)
      Recurse ( y, number - 1 )
   else
      for x in range (y)
      whatever()
person Ozair Kafray    schedule 25.08.2011
comment
Структура этой функции развеяла туман в моей голове при преобразовании моего кода в рекурсивный. Спасибо х 1000000! - person Anti Earth; 25.08.2011
comment
Рекурсия, безусловно, является одним из способов решения этой проблемы, но приведенный выше алгоритм неверен; независимо от значения number он повторяется только y раза. См. решение, предоставленное @RobertMartin, для правильного кода/алгоритма. - person Loax; 08.08.2014
comment
@Loax прав. Этот ответ неверен. Логика этого ответа не работает. - person Arulx Z; 13.10.2015
comment
Этот ответ неверен. Его следует отменить в качестве решения. - person Dave S; 23.02.2019

Я не понимаю, почему вы не можете использовать произведение границ и сделать

for x in range(y exp n)

где n - количество циклов... Вы говорите, что y exp n будет огромным, но я уверен, что python справится с этим.

Однако, как насчет какого-то рекурсивного алгоритма?

def loop_rec(y, n):
    if n >= 1:
        for x in range(y):
            loop_rec(y, n - 1)
    else:
       whatever()
person Robert Martin    schedule 25.08.2011
comment
Он был слишком большим для питона! :( - person Anti Earth; 25.08.2011
comment
Святое дерьмо! Тогда я впечатлен вашей программой! Удачи в рекурсии - person Robert Martin; 25.08.2011
comment
На самом деле это лучшее решение и, возможно, одно из немногих, которые сработали! - person Arulx Z; 13.10.2015

Рекурсия будет вашим лучшим выбором. Рассмотрим, что он должен делать в базовом и рекурсивном случае.

Код не указан, согласно запросу.

person outis    schedule 25.08.2011
comment
Да, это классический случай рекурсивности. - person m0skit0; 25.08.2011

Ну вот. Пусть диапазоны будут вашими диапазонами, оперируйте результатом, когда вам нужно.

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]

Тестирование со следующим даст тот же результат:

for x in range(*ranges[0]):
    for y in range(*ranges[1]):
        for z in range(*ranges[2]):
            print [x,y,z]
person robert king    schedule 25.08.2011
comment
Наконец нашел итеративное решение :) Это хороший код! - person Rahul Goswami; 22.06.2018

Хорошая реализация проблемы с переменным количеством циклов For Loops:

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 

Пример использования:

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)

Код возвращает то же самое, что и этот код:

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

Вы рассматривали xrange ?

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

И если вы превысите даже предел xrange, вы можете использовать itertool

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

(предыдущий ответ itertool неправильно использовал n для диапазона вместо y)

person MatthieuW    schedule 25.08.2011
comment
... но на самом деле ваша реальная проблема не первая, которую вы описываете, поскольку вам нужно дополнительное право (180) в каждом цикле. Так что рекурсивно - правильный ответ - person MatthieuW; 25.08.2011

Мой ответ запоздал, но предположим, что вы хотите сделать несколько циклов, например. печатать некоторый диапазон несколько раз. Тогда правильная версия этой рекурсии:

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)

Это создаст три цикла for с диапазоном (4)

Если вы хотите поиграть с динамическим диапазоном, вот несколько вариантов:

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)

который распечатает:

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)

который выведет:

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

Лучший вариант, который использует только один цикл for (меньше ввода), следующий:

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)

выведет:

0 1 2 3 4 
0 1 2 3 
0 1 2 
0 1 
0 
person youth4ever    schedule 03.10.2016

Вот еще вариант итеративного решения, мне кажется проще. Идея состоит в том, чтобы использовать аналогию с системой счисления на основе 10 или X. Где вы в основном увеличиваете свое число/количество на единицу каждый раз, но представление меняется в зависимости от базы. т.е. если основание равно 10, то число меняется на 1 .. 9 10 11 .. 19 20... Представьте, что мы хотим выполнить цикл по i,j,k от 0 до 9 для каждого. Мы запускаем цикл для счетчика в диапазоне (101010) и берем цифры в качестве значений числа. Например. 731 означает i=7,j=3, k=1. Чтобы сделать случай более общим, когда диапазон для каждого i/j/... различен, мы берем этот диапазон по модулю:

`

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

Вывод будет:

[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]

`

person squark    schedule 07.07.2020