Добавление элемента в список каждый второй элемент - PullRequest
3 голосов
/ 05 ноября 2019

Я хочу вставлять элемент в существующий список каждый второй элемент.

Скажем, список fruits = ["banana", "apple", "mango", "kiwi"], чтобы добавить элемент "peach", что я делаю:

fruits = ["banana", "apple", "mango", "kiwi"]
fruits_2 = list(fruits)

for i in range(len(fruits)):
    fruits_2.insert(2*i + 1, "peach")

print(fruits_2)

и выводом является

['banana', 'peach', 'apple', 'peach', 'mango', 'peach', 'kiwi', 'peach']

, что я и хочу, но я чувствую, что, возможно, есть лучший и более краткий способ сделать это, не создавая второй список.

Ответы [ 4 ]

6 голосов
/ 05 ноября 2019

Использование zip вместе с itertools.repeat и itertools.chain.

>>> from itertools import chain, repeat
>>> fruits = ["banana", "apple", "mango", "kiwi"]
>>> list(chain.from_iterable(zip(fruits, repeat("peach"))))
['banana', 'peach', 'apple', 'peach', 'mango', 'peach', 'kiwi', 'peach']

repeat создает бесконечную последовательность 'peach'. zip создает последовательность пар, состоящую из одного элемента из фруктов, за которым следует экземпляр 'peach'. chain.from_iterable «сводит» последовательность пар в одну последовательность, а list создает конкретный список из последовательности.


Просмотр промежуточных шагов:

>>> from itertools import islice
>>> list(islice(repeat("peaches"), 5))
['peaches', 'peaches', 'peaches', 'peaches', 'peaches']

>>> zip(fruits, repeat("peaches"))
[('banana', 'peaches'), ('apple', 'peaches'), ('mango', 'peaches'), ('kiwi', 'peaches')]

Этот подход сводится к серии appends к новому списку, что-то вроде

result = []
for x in fruits:
    result.append(x)
    result.append("peaches")

Но вместо жесткого кодирования аргументов append, вы выбираете их из парыитераторов:

def peach_source():
    while True:
        yield "peach"

def fruit_source(fruits):
    for x in fruits:
        yield x

result = []
peaches = peach_source()
fruits = fruit_source(fruits)  # Yes, this is highly redundant; just showing the similarity to peach_source
done = False
while not done:
    try:
        result.append(next(fruits))
    except StopIteration:
        done = True
    result.append(next(peaches))

itertools.repeat создает peach_source для вас. zip обрабатывать чередование между извлечением фруктов и персиком. chain.from_iterable определяет действие добавления к result, а list фактически выполняет добавления.

1 голос
/ 05 ноября 2019

просмотр списка + опция выравнивания - импорт не требуется:

fruits = ["banana", "apple", "mango", "kiwi"]
add = 'peach'
out = [i for s in [[f, add] for f in fruits] for i in s]
out
# ['banana', 'peach', 'apple', 'peach', 'mango', 'peach', 'kiwi', 'peach']

опция продукта itertools:

fruits = ["banana", "apple", "mango", "kiwi"]
add = ["peach"]
out = list(itertools.chain(*itertools.product(fruits, add)))
out
# ['banana', 'peach', 'apple', 'peach', 'mango', 'peach', 'kiwi', 'peach']

некоторые значения времени:

%timeit list(chain.from_iterable(zip(fruits, repeat(*add))))
910 ns ± 19.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit list(itertools.chain(*itertools.product(fruits, add)))
1.07 µs ± 13.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit [fruits[i // 2] if i % 2 == 0 else "peach" for i in range(len(fruits) * 2)]
1.62 µs ± 40.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit [i for s in [[f, *add] for f in fruits] for i in s]
2.16 µs ± 630 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

однако самый быстрый вариант кажется самым простым:

def func(fruits):
    result = []
    for x in fruits:
        result.append(x)
        result.append("peaches")
    return result

%timeit func(fruits)
746 ns ± 15.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1 голос
/ 05 ноября 2019

Просто с " двойной длиной " (и четная / нечетная позиция) магия:

fruits = ["banana", "apple", "mango", "kiwi"]
new_fruits = [fruits[i // 2] if i % 2 == 0 else 'peach' for i in range(len(fruits) * 2)]
print(new_fruits)

Выход:

['banana', 'peach', 'apple', 'peach', 'mango', 'peach', 'kiwi', 'peach']

ЕслиПродолжая работу с itertools подходами itertools.zip_longest функция представляется наиболее быстрой:

new_fruits = [v for v in itertools.zip_longest(fruits, add, fillvalue=add[0])]

Время:

In [33]: fruits = ["banana", "apple", "mango", "kiwi"]                                                      

In [34]: add = ["peach"]                                                                                    

In [35]: %timeit [v for v in itertools.zip_longest(fruits, add, fillvalue=add[0])]                          
859 ns ± 16.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [36]: %timeit list(itertools.chain.from_iterable(zip(fruits, itertools.repeat(*add))))                   
992 ns ± 40.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [37]: %timeit list(itertools.chain(*itertools.product(fruits, add)))                                     
1.05 µs ± 18 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [38]: %timeit [i for s in [[f, *add] for f in fruits] for i in s]                                        
1.25 µs ± 73.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [39]: %timeit [fruits[i // 2] if i % 2 == 0 else "peach" for i in range(len(fruits) * 2)]                
1.29 µs ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
0 голосов
/ 05 ноября 2019

Точно так же, как вы, но в первом списке:

fruits = ["banana", "apple", "mango", "kiwi"]
for i in range(len(fruits)):
    fruits.insert(i*2+1, "peach")

>>> fruits
['banana', 'peach', 'apple', 'peach', 'mango', 'peach', 'kiwi', 'peach']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...