Вложенная одна строка для циклов

104

Написал эту функцию на питоне, который транспонирует матрицу:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

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

  1. В каком порядке выполняется этот цикл for?
  2. Если бы у меня был тройной вложенный цикл for, в каком порядке он выполнялся бы?
  3. Что было бы равным равному невложенному циклу for?

Дано,

[ function(i,j) for i,j in object ]
  1. Какого типа должен быть объект, чтобы использовать эту структуру цикла?
  2. В каком порядке i и j присваиваются элементам в объекте?
  3. Можно ли смоделировать это с помощью другой структуры цикла for?
  4. Можно ли вложить этот цикл for в аналогичную или другую структуру цикла for? А как бы это выглядело?

Также приветствуется дополнительная информация.

Ашер Гарланд
источник

Ответы:

171

Лучший источник информации - официальный учебник Python по составлению списков . Понимание списков почти такое же, как и циклы for (конечно, любое понимание списка может быть записано в виде цикла for), но они часто быстрее, чем использование цикла for.

Взгляните на этот более длинный список из учебника ( ifчасть фильтрует понимание, только части, которые передают оператор if, передаются в последнюю часть понимания списка (здесь (x,y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Он точно такой же, как и этот вложенный цикл for (и, как сказано в руководстве, обратите внимание, что порядок for и if одинаков).

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Основное различие между пониманием списка и циклом for заключается в том, что последняя часть цикла for (где вы что-то делаете) идет в начале, а не в конце.

На ваши вопросы:

Какого типа должен быть объект, чтобы использовать эту структуру цикла?

Итерацию . Любой объект, который может генерировать (конечный) набор элементов. К ним относятся любой контейнер, списки, наборы, генераторы и т. Д.

В каком порядке i и j присваиваются элементам в объекте?

Они назначаются в том же порядке, в котором они генерируются из каждого списка, как если бы они были во вложенном цикле for (для вашего первого понимания вы получите 1 элемент для i, затем каждое значение из j, 2-й элемент в i, затем каждое значение из j и т. д.)

Можно ли смоделировать это с помощью другой структуры цикла for?

Да, уже показано выше.

Можно ли вложить этот цикл for в аналогичную или другую структуру цикла for? А как бы это выглядело?

Конечно, но это не лучшая идея. Вот, например, список списков персонажей:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]
Джефф Тратнер
источник
Интересно, чем они руководствовались при выборе порядка размещения в двойном вложении. Я считаю другой способ более естественным (для y, а не для x в вашем примере). Я просто понимаю, что после 3 лет работы с python (не очень, но все же ...) и использования таких циклов !!
Thomas
@Thomas Я также считаю другой способ более интуитивным. Я считаю, что выбор был сделан исключительно из соображений удобства. Выполнение этого более интуитивно понятным способом означало бы иметь дело с неразрешенными символами, пока он не найдет их позже в операторе. Попробуйте выполнить синтаксический анализ каждого банана, кожуры каждого банана для каждого города. Бананастора в каждом городе на бумаге. Не все так просто. А наоборот, красиво и легко.
Пиджонг,
30

Возможно, вас заинтересует itertools.product, который возвращает итерируемый, дающий кортеж значений из всех итераций, которые вы ему передаете. То есть itertools.product(A, B)выдает все значения формы (a, b), откуда aберутся значения Aи откуда берутся bзначения B. Например:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

Это печатает:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

Обратите внимание, как последний аргумент, переданный itertools.productв "внутренний". Как правило, равноitertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]

Линн
источник
4

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

  1. Было бы эквивалентно

    для j в диапазоне (0, ширина): для i в диапазоне (0, высота): m [i] [j]

  2. Примерно так же, как и для циклов, справа налево. Но синтаксис понимания списка более сложен.

  3. Я не уверен, что задает этот вопрос


  1. Любой итерируемый объект, который дает итерируемые объекты, которые дают ровно два объекта (что за глоток - т.е. [(1,2),'ab']был бы действительным)

  2. Порядок, в котором объект уступает место при итерации. iидет к первому урожаю, jвторому.

  3. Да, но не так красиво. Я считаю, что это функционально эквивалентно:

    l = список ()
    для i, j в объекте:
        l.append (функция (i, j))
    

    или даже лучше использовать карту :

    map(function, object)

    Но, конечно , функция бы получить i, jсам.

  4. Разве это не тот же вопрос, что и 3?

корыльский князь
источник
2

Вы можете использовать два цикла for в одной строке с помощью zipфункции

Код:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

Вывод:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

Итак, с помощью функции zip мы можем использовать два цикла for или перебирать два списка в одной строке.

Мухаммад Аббас
источник
-1

Ниже приведен код лучших примеров для вложенных циклов. При использовании двух циклов for помните, что выходные данные первого цикла являются входными данными для второго цикла. Завершение цикла также важно при использовании вложенных циклов

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
Рамешбабу Редди
источник