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

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

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

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

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

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

  • Извлечение строк из вложенных списков в Python
  • Как получить нормальное распределение в диапазоне в numpy?
  • Django: Syncdb неправильно предупреждает, что поле «многие ко многим» устарело
  • КАК использовать Pycharm для отладки скрипта python?
  • Как python препятствует подклассу класса?
  • Одновременная функциональность.
  • Путь между двумя узлами
  • numpy: массив 1D с различной формой
  • 15 Solutions collect form web for “Цикл списка из чередующихся сторон”

     >>> [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, чем итерация.

    cycle между получением предметов от переднего и iter и reversed . Просто убедитесь, что вы остановились на len(a) с помощью islice .

     from itertools import islice, cycle iters = cycle((iter(a), reversed(a))) b = [next(it) for it in islice(iters, len(a))] >>> b [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] 

    Это можно легко поместить в одну строку, но тогда становится намного труднее прочитать:

     [next(it) for it in islice(cycle((iter(a),reversed(a))),len(a))] 

    Помещение в одну строку также помешает вам использовать другую половину итераторов, если вы хотите:

     >>> iters = cycle((iter(a), reversed(a))) >>> [next(it) for it in islice(iters, len(a))] [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] >>> [next(it) for it in islice(iters, len(a))] [5, 4, 6, 3, 7, 2, 8, 1, 9, 0] 

    Очень хороший однострочный слой в 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 даст вам дублирующее среднее значение, поэтому будьте предупреждены.

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

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

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

    Для удовольствия, вот вариант itertools:

     >>> a = [0,1,2,3,4,5,6,7,8,9] >>> list(chain.from_iterable(izip(islice(a, len(a)//2), reversed(a)))) [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] 

    Это работает там, где len(a) четное. Для этого потребуется специальный код для ввода с нечетным удлинением.

    Наслаждайтесь!

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

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

    Основным принципом вашего вопроса является так называемый алгоритм roundrobin. Страница itertools содержит возможную ее реализацию:

     from itertools import cycle, islice def roundrobin(*iterables): """This function is taken from the python documentation! roundrobin('ABC', 'D', 'EF') --> ADEBFC Recipe credited to George Sakkis""" pending = len(iterables) nexts = cycle(iter(it).__next__ for it in iterables) # next instead of __next__ for py2 while pending: try: for next in nexts: yield next() except StopIteration: pending -= 1 nexts = cycle(islice(nexts, pending)) 

    так что все, что вам нужно сделать, это разделить ваш список на два подсписок, начиная с левого и с правого конца:

     import math mid = math.ceil(len(a)/2) # Just so that the next line doesn't need to calculate it twice list(roundrobin(a[:mid], a[:mid-1:-1])) # Gives you the desired result: [0, 9, 1, 8, 2, 7, 3, 6, 4, 5] 

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

     list(roundrobin(a, reversed(a)))[:len(a)] 

    или используя его как явный генератор со next :

     rr = roundrobin(a, reversed(a)) [next(rr) for _ in range(len(a))] 

    или быстрый вариант, предложенный @Tadhg McDonald-Jensen (спасибо!):

     list(islice(roundrobin(a,reversed(a)),len(a))) 

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

     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))) 
     mylist = [0,1,2,3,4,5,6,7,8,9] result = [] for i in mylist: result += [i, mylist.pop()] 

    Заметка:

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

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

     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 = range(10) [val for pair in zip(a[:len(a)//2],a[-1:(len(a)//2-1):-1]) for val in pair] 

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

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

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

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

     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] 
    Interesting Posts
    Python - лучший язык программирования в мире.