Как добавлять каждое n-е в последовательности?

#python

#python

Вопрос:

Если у меня есть список:

 ["a1", "b1", "c1", "a2", "b2", "c2", "a3", "b3", "c3"]
  

и я хочу создать новый список, подобный:

 ["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"]
  

Я пытаюсь сделать это в цикле for, чтобы последовательно добавлять к новому списку:

 newlist = []
for i in oldlist:
    newlist.append(oldlist[i])
    newlist.append(oldlist[2*i])
    newlist.append(oldlist[3*i])
    i 3
  

Проблема с моим кодом в том, что он будет добавлять все значения i or i*3 first за один раз, вместо того, чтобы давать шанс каждой n -й версии i.

Комментарии:

1. Вы можете использовать sorted функцию для сортировки вашего списка, если это ваша конечная цель.

Ответ №1:

Вы могли бы изменять последовательность с желаемыми смещениями, используя itertools для преобразования обратно в одномерный список.

 >>> import itertools
>>> d =  ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'a3', 'b3', 'c3']
>>> list(itertools.chain.from_iterable([d[::3], d[1::3], d[2::3]]))
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
  

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

 >>> import numpy as np
>>> d =  np.array(['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'a3', 'b3', 'c3'])
>>> np.reshape(d, (d.size//3, 3)).T.flatten()
array(['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'], dtype='<U2')
  

Ответ №2:

Допустим, вы хотите, чтобы интервал был n = 3

 >>> a=[1,2,3,11,22,33,111,222,333]
>>> res=[]
>>> n=3
>>> for i in range(0,n):
...     for z in a[i::n]:
...         res.append(z)
... 
>>> 
>>> res
[1, 11, 111, 2, 22, 222, 3, 33, 333]
  

Более pythonic

 >>> a=['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'a3', 'b3', 'c3']
>>> res = [val for i in range(3) for val in a[i::3]]
>>> res
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
  

где a[i::3] просто проходит список, начиная с i-го индекса, с шагом в 3.

Ответ №3:

Интересной особенностью zip является его способность группировать входные данные в группы фиксированной длины без явного нарезания. grouper Рецепт позволяет преобразовать в группы фиксированной длины, которые затем можно распаковать для следующего раунда zip редактирования таким образом, чтобы соединить первые элементы каждой группы:

 >>> lst = ["a1", "b1", "c1", "a2", "b2", "c2", "a3", "b3", "c3", 'a4', 'b4', 'c4']  # Added three more elements so it's clear it's three groups of four, three of three being harder to see
>>> list(zip(*[iter(lst)]*3))  # Grouped sequentially so a is first element of each group
[('a1', 'b1', 'c1'),
 ('a2', 'b2', 'c2'),
 ('a3', 'b3', 'c3'),
 ('a4', 'b4', 'c4')]

>>> list(zip(*zip(*[iter(lst)]*3))) # Unpack and zip again to group a's with a's, b's with b's, etc.
[('a1', 'a2', 'a3', 'a4'), ('b1', 'b2', 'b3', 'b4'), ('c1', 'c2', 'c3', 'c4')]

>>> from itertools import chain
>>> list(chain.from_iterable(zip(*zip(*[iter(lst)]*3))))  # Flatten out to single list
['a1', 'a2', 'a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c1', 'c2', 'c3', 'c4']
  

Вы можете достичь того же результата с помощью:

 >>> list(chain.from_iterable(lst[i::3] for i in range(3)))
['a1', 'a2', 'a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c1', 'c2', 'c3', 'c4']
  

multi- zip просто переносит всю работу на встроенные модули (вообще без зацикливания на уровне Python). Плюс последний на целых два символа длиннее и кажется слишком похожим на ответ CoryKramer . 🙂 Тем не менее, последнее лучше, если ваш ввод не имеет четной длины; zip останавливает итерацию, когда исчерпан самый короткий итерируемый параметр, в то время как itertools.zip_longest приходится использовать значения-заполнители. Фактическое нарезание и сглаживание позволяет избежать этой проблемы.

Комментарии:

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

2. @darksky: 😀 На самом деле я не рекомендую этот подход. Код ближе к концу ( chain ввод выражения генератора, создающего фрагменты) прекрасен, но остальное в основном просто для развлечения. Если бы я должен был использовать предыдущий код, я бы использовал его исключительно после определения grouper рецепта, так что это выглядело бы как list(zip(*grouper(lst, 3)) , что все еще не очень здорово, но явно менее уродливо.