Функция для условного цикла - PullRequest
0 голосов
/ 01 апреля 2012

Хорошо, это полный код, с которым я работаю. Теперь я обеспечил ввод и вывод. Надеюсь, это имеет больше смысла, что мои абсурдные вопросы раньше .....

def get_positions(xs, item):    
    if isinstance(xs, list):
        for i, it in enumerate(xs):
            for pos in get_positions(it, item):
                yield (i,) + pos
    elif xs == item:
        yield ()
blocks = [-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12,14,16]
startcombos = [[-12], [-12, -10], [-12, -10, -8], [-12, -10, -8, -6], [-12, -10, -8, -6, -4], [-12, -10,-8, -6, -4, -2], [-12, -10, -8, -6, -4, -2, 0], [-12, -10, -8, -6, -4, -2, 0, 2], [-12, -10, -8, -6, -4, -2, 0, 2, 4], [-12, -10, -8, -6, -4, -2, 0, 2, 4, 6], [-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8], [-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10], [-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12], [-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14], [-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16]]
combos = [[-10], [-10, -8], [-10, -8, -6], [-10, -8, -6, -4], [-10, -8, -6, -4, -2], [-10, -8, -6,-4, -2, 0], [-10, -8, -6, -4, -2, 0, 2], [-10, -8, -6, -4, -2, 0, 2, 4], [-10, -8, -6, -4, -2, 0, 2, 4, 6], [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8], [-10, -8, -6, -4, -2, 0, 2, 4, 6,8, 10], [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12], [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14], [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16], [-8], [-8, -6], [-8, -6, -4], [-8, -6, -4, -2], [-8, -6, -4, -2, 0], [-8, -6, -4, -2, 0, 2], [-8, -6, -4, -2, 0, 2, 4], [-8, -6, -4, -2, 0, 2, 4, 6], [-8, -6, -4, -2, 0, 2, 4, 6, 8], [-8, -6, -4, -2, 0, 2, 4, 6, 8, 10], [-8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12], [-8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14], [-8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16], [-6], [-6, -4], [-6, -4, -2], [-6, -4, -2, 0], [-6, -4, -2, 0, 2], [-6, -4, -2, 0, 2, 4], [-6, -4, -2, 0, 2, 4, 6], [-6, -4, -2, 0, 2, 4, 6, 8], [-6, -4, -2, 0, 2, 4, 6, 8, 10], [-6, -4, -2, 0, 2, 4, 6, 8, 10, 12], [-6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14], [-6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16], [-4], [-4, -2], [-4, -2, 0], [-4, -2, 0, 2], [-4, -2, 0, 2, 4], [-4, -2, 0, 2, 4, 6],[-4, -2, 0, 2, 4, 6, 8], [-4, -2, 0, 2, 4, 6, 8, 10], [-4, -2, 0, 2, 4, 6, 8, 10, 12], [-4, -2, 0, 2, 4, 6, 8, 10, 12, 14], [-4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16], [-2], [-2, 0],[-2, 0, 2], [-2, 0, 2, 4], [-2, 0, 2, 4, 6], [-2, 0, 2, 4, 6, 8], [-2, 0, 2, 4, 6, 8, 10], [-2, 0, 2, 4, 6, 8, 10, 12], [-2, 0, 2, 4, 6, 8, 10, 12, 14], [-2, 0, 2, 4, 6, 8, 10, 12, 14, 16], [0], [0, 2], [0, 2, 4], [0, 2, 4, 6], [0, 2, 4, 6, 8], [0, 2, 4, 6, 8, 10], [0,2, 4, 6, 8, 10, 12], [0, 2, 4, 6, 8, 10, 12, 14], [0, 2, 4, 6, 8, 10, 12, 14, 16], [2], [2, 4], [2, 4, 6], [2, 4, 6, 8], [2, 4, 6, 8, 10], [2, 4, 6, 8, 10, 12], [2, 4, 6, 8, 10, 12, 14], [2, 4, 6, 8, 10, 12, 14, 16], [4], [4, 6], [4, 6, 8], [4, 6, 8, 10], [4, 6, 8, 10,12], [4, 6, 8, 10, 12, 14], [4, 6, 8, 10, 12, 14, 16], [6], [6, 8], [6, 8, 10], [6, 8, 10, 12], [6, 8, 10, 12, 14], [6, 8, 10, 12, 14, 16], [8], [8, 10], [8, 10, 12], [8, 10, 12, 14], [8, 10, 12, 14, 16], [10], [10, 12], [10, 12, 14], [10, 12, 14, 16], [12], [12, 14], [12, 14, 16], [14], [14, 16], [16]]

temp = []
for i in range(len(startcombos)):   
    for j in list(get_positions(combos,startcombos[i][-1]+2)):
        if j[-1]==0 and combos[j[0]][-1]!=blocks[-1]:

            for k in list(get_positions(combos,combos[j[0]][-1]+2)):                
                if k[-1]==0 and combos[k[0]][-1]!=blocks[-1]:

                    for l in list(get_positions(combos,combos[k[0]][-1]+2)):
                        if l[-1]==0 and combos[l[0]][-1]==blocks[-1]:
                            temp.append(tuple(startcombos[i]))
                            temp.append(tuple(combos[j[0]]))
                            temp.append(tuple(combos[k[0]]))
                            temp.append(tuple(combos[l[0]]))
                            combinations.append(temp)
                            temp = []

Это код для генерации температуры длины 4. Если длина комбинаций увеличивается, я бы включил другое условие в больший цикл, как это

for i in range(len(startcombos)):   
    for j in list(get_positions(combos,startcombos[i][-1]+2)):
        if j[-1]==0 and combos[j[0]][-1]!=blocks[-1]:

            for k in list(get_positions(combos,combos[j[0]][-1]+2)):                
                if k[-1]==0 and combos[k[0]][-1]!=blocks[-1]:               

                    for l in list(get_positions(combos,combos[k[0]][-1]+2)):
                        if l[-1]==0 and combos[l[0]][-1]!=blocks[-1]:

                            for m in list(get_positions(combos,combos[l[0]][-1]+2)):
                                if m[-1]==0 and combos[m[0]][-1]==blocks[-1]:
                                    temp.append(tuple(startcombos[i]))
                                    temp.append(tuple(combos[j[0]]))
                                    temp.append(tuple(combos[k[0]]))
                                    temp.append(tuple(combos[l[0]]))
                                    temp.append(tuple(combos[m[0]]))                                        
                                    combinations.append(temp)
                                    temp = []

Это создаст темп длиной 5. Как вы заметили, изменились первое и последнее условия и циклы, средняя часть осталась прежней. Как написать функцию или любой другой способ, которым я могу достичь ее с переменной длиной?

Теперь то, что я получил бы здесь, это, в основном, комбинации, которые получаются путем предоставления определенных условий. Я знаю, что я мог бы попробовать Python-комбинации из itertools, но генерировать все комбинации просто не стоит, если я хочу конкретные комбинации и, кроме того, вычислительное время также важно. Таким образом, это дало бы следующий вывод для длины 4

combinations[0] = [[-12],[-10],[-8],[-6,-4,-2,0,2,4,6,8,10,12,14,16]]

и т. Д., Число которых 364.

Для длины 5 он даст в общей сложности 1001 комбинацию, первой из которых будет эта

combinations[0] = [[-12],[-10],[-8],[-6],[-4,-2,0,2,4,6,8,10,12,14,16]]

1 Ответ

2 голосов
/ 01 апреля 2012

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

Во-первых, позвольте мне просто удовлетворить Pythonistas, читая это, сказав, что Pythonic способ сделать это, вероятно, предполагает использование функции itertools.product и, вероятно, встроенной функции filter().

Помимо этого, я думаю, вам следует ознакомиться с концепцией рекурсии , потому что она позволяет вам как бы "наивно" придумывать простые решения таких проблем, не полагаясь на сладкое - такой язык, как Python, чтобы дать вам потрясающую библиотеку, полную функций генератора.

Допустим, у вас есть несколько списков в некоторых списках списков, например:

nested = [[a1, a2, a3, ..., ana],
          [b1, b2, b3, ..., bnb],
          ...
          [x1, x2, x3, ..., xnx]]

И вы хотите перебрать псевдолексографически через последовательности, которые содержат по одному элементу из каждого из этих списков, например:

a1 b1 c1 ... x1
a1 b1 c1 ... x2
...
a2 b1 c1 ... x1
a2 b1 c1 ... x2
...
...
ana bnb cnc ... x(nx - 1)
ana bnb cnc ... xnx

Трудно сделать это с обычными статическими циклами for, потому что вы обычно должны печатать каждый из них, верно? Как вы набираете переменное число циклов for? Своим наивным приемом для этого является использование рекурсии (опять же, это не самый питонский способ).

Рекурсия говорит: «Хорошо, у меня есть проблема. Эта проблема в основном заключается в том, чтобы просто сделать что-то маленькое с частью моих данных, а затем рекурсивно решить ту же проблему на Остальные данные. Когда у меня больше нет данных для работы, я, вероятно, справился с этой подзадачей. "

Простой классический пример рекурсии - вычисление суммы списка чисел:

def sum_nums(nums):
    # The "base case" is usually checked first. This is when your
    # recursion has run out of things to do, it just returns a simple value.
    if nums == []:
        return 0
    # The "recursive case" is the real meat and potatoes of recursion.
    # It says to take the first number and add it to the sum_nums of the
    # rest of the numbers in the list (which may be empty, hence the base case!).
    else:
        return nums[0] + sum_nums(nums[1:])

Подумай об этом. Понимать это. Медитируй об этом и забудь, что понимаешь это. Сделайте психоделики и подумайте еще раз. Очень важно иметь возможность вытаскивать рекурсивные хаки из своей задницы на лету.

Теперь более продвинутая техника - передавать значения в рекурсивной функции. В этом случае это может быть полезно, потому что вы не хотите ничего делать, пока не приступите к базовому случаю. Я оставил базовый случай, чтобы вы могли реализовать себя, если хотите.

def print_lexo_lists(items, lists):
    if lists == []:
        # What do you want to do if you've taken a single item from each of your
        # lists and put it in the list called "items"?
    else:
        # Take each item from the current level and pass it down in turn to the
        # next deeper level, adding it to the running list of "items". Remove
        # the current level from the list of "lists" before passing it down.
        # In this way you're "using up" the current level, and the "lists"
        # structure is getting smaller at each level of recursive depth, until
        # you reach the base case (when it is an empty list)
        for current_item in lists[0]:
            print_lexo_lists(items + [current_item], lists[1:])

Надеюсь, вы сможете следовать этому в некоторой степени. Я настоятельно рекомендую вам реализовать это, прежде чем пытаться выполнить следующий способ, который на самом деле является правильным способом создания вложенных циклов for в Python путем генерации декартового произведения из списков:

from itertools import product
for items in product(*lists):
    print ' '.join(items)
...