python iterate - Цикл списка из чередующихся сторон




list with (13)

Один из способов сделать это для списков четного размера (вдохновленный here ):

a = range(10)

b = [val for pair in zip(a[:5], a[5:][::-1]) for val in pair]

Учитывая список

a = [0,1,2,3,4,5,6,7,8,9]

как я могу получить

b = [0,9,1,8,2,7,3,6,4,5]

То есть, создайте новый список, в котором каждый последующий элемент поочередно берется с двух сторон исходного списка?


Совсем не изящно, но это неуклюжий однострочный:

a = range(10)
[val for pair in zip(a[:len(a)//2],a[-1:(len(a)//2-1):-1]) for val in pair]

Обратите внимание, что предполагается, что вы делаете это для списка четной длины. Если это ломается, тогда это ломается (оно понижает средний срок). Заметьте, что у меня есть идея here .


Очень хороший однострочный слой в Python 2.7:

results = list(sum(zip(a, reversed(a))[:len(a)/2], ()))
>>>> [0, 9, 1, 8, 2, 7, 3, 6, 4, 5]

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

В Python 3 zip возвращает генератор, поэтому вам нужно использовать islice от itertools :

from itertools import islice
results = list(sum(islice(zip(a, reversed(a)),0,int(len(a)/2)),()))

Edit : Похоже, что это работает отлично только для длин четного списка - длины нечетного списка будут пропускать средний элемент :( Небольшая поправка для int(len(a)/2) к int(len(a)/2) + 1 даст вам дублирующее среднее значение, поэтому будьте предупреждены.


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

a = [0,1,2,3,4,5,6,7,8,9]
mid = len(a)//2
l = []
for x, y in zip(a[:mid], a[:mid-1:-1]):
    l.append(x)
    l.append(y)
# if the length is odd
if len(a) % 2 == 1:
    l.append(a[mid])
print(l)

Вывод:

[0, 9, 1, 8, 2, 7, 3, 6, 4, 5]

Не уверен, может ли это быть написано более компактно, но оно эффективно, поскольку оно использует только итераторы / генераторы

a = [0,1,2,3,4,5,6,7,8,9]

iter1 = iter(a)
iter2 = reversed(a)
b = [item for n, item in enumerate(
        next(iter) for _ in a for iter in (iter1, iter2)
    ) if n < len(a)]

>>> [a[-i//2] if i % 2 else a[i//2] for i in range(len(a))]
[0, 9, 1, 8, 2, 7, 3, 6, 4, 5]

Объяснение:
Этот код выбирает числа от начала ( a[i//2] ) и от конца ( a[-i//2] ) от a , чередуясь ( if i%2 else ). Общее количество len(a) выбрано, поэтому это не вызывает никаких негативных последствий, даже если len(a) нечетно.
[-i//2 for i in range(len(a))] дает 0, -1, -1, -2, -2, -3, -3, -4, -4, -5 ,
[ i//2 for i in range(len(a))] дает 0, 0, 1, 1, 2, 2, 3, 3, 4, 4 ,
и i%2 чередуется между False и True ,
поэтому индексы, которые мы извлекаем из a равны: 0, -1, 1, -2, 2, -3, 3, -4, 4, -5 .

Моя оценка питоничности:
Самое приятное в этом однострочном заключается в том, что оно короткое и демонстрирует симметрию ( +i//2 и -i//2 ).
Плохо, однако, состоит в том, что эта симметрия обманчива:
Можно подумать, что -i//2 были такими же, как i//2 с перевернутым знаком. Но в Python целочисленное деление возвращает пол результата вместо усечения в нуль. Итак, -1//2 == -1 .
Кроме того, я нахожу доступ к элементам списка по индексу меньше pythonic, чем итерация.


Не очень отличается от некоторых других ответов, но он избегает условного выражения для определения знака индекса.

a = range(10)
b = [a[i // (2*(-1)**(i&1))] for i in a]

i & 1 чередуется между 0 и 1. Это приводит к тому, что экспонента чередуется между 1 и -1. Это приводит к тому, что делитель индекса чередуется между 2 и -2, что заставляет индекс чередоваться от конца к концу по мере увеличения i . Последовательность представляет a[0] , a[-1] , a[1] , a[-2] , a[2] , a[-3] и т. Д.

(Я повторяю i над a так как в этом случае каждое значение a равно его индексу. В общем случае итерация по range(len(a)) .)


Две версии пока не видны:

b = list(sum(zip(a, a[::-1]), ())[:len(a)])

а также

import itertools as it

b = [a[j] for j in it.accumulate(i*(-1)**i for i in range(len(a)))]

Я бы сделал что-то подобное

a = [0,1,2,3,4,5,6,7,8,9]
b = []
i = 0
j = len(a) - 1
mid = (i + j) / 2
while i <= j:
    if i == mid and len(a) % 2 == 1:
        b.append(a[i])
        break
    b.extend([a[i], a[j]])
    i = i + 1
    j = j - 1

print b

Вы можете просто pop вперед и назад:

b = [a.pop(-1 if i%2 else 0) for i in range(len(a))]

Примечание. Это уничтожает исходный список, a .


mylist = [0,1,2,3,4,5,6,7,8,9]
result = []

for i in mylist:
    result += [i, mylist.pop()]

Заметка:

Остерегайтесь: так же, как @Tadhg McDonald-Jensen сказал (см. Комментарий ниже), он уничтожит половину исходного объекта списка.


Используйте правильные инструменты .

from toolz import interleave, take

b = list(take(len(a), interleave((a, reversed(a)))))

Во-первых, я попробовал нечто подобное решению Раймонда Хеттингера с itertools (Python 3).

from itertools import chain, islice

interleaved = chain.from_iterable(zip(a, reversed(a)))
b = list(islice(interleaved, len(a)))

Python 3.5 представил новый, более быстрый метод для прохода по каталогу os.scandir().

Пример:

for file in os.scandir('/usr/bin'):
    line = ''
    if file.is_file():
        line += 'f'
    elif file.is_dir():
        line += 'd'
    elif file.is_symlink():
        line += 'l'
    line += '\t'
    print("{}{}".format(line, file.name))






python algorithm list iteration