Replacing every other position in a list

Viewed 124

I'm trying to make something that allows me to replace every other position in a list with a single item:

l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
l[::2] = "A"
print(l)

I'm expecting something like:

["A", 1, "A," 3, "A", 5, "A", 7, "A", 9, "A"]

I've tried different positions of indexing [::] but either get an error or a result that doesn't include the rest of the list.

Instead I get this:

ValueError: attempt to assign sequence of size 1 to extended slice of size 2
3 Answers

The slice is correct, but you need to provide a sequence with enough elements to fill all the elements.

l[::2] = ["A"] * math.ceil(len(l)/2)

Edit: Barmar's answer is much better, so long as you're okay with importing the math library.

Rough speed comparison at 10,000 loops (assuming you don't turn the list into a generator, otherwise the list comprehension becomes slightly faster overall):

import math, time

def slicing(n):
    for _ in range(n):
        l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        l[::2] = ["A"] * math.ceil(len(l)/2)

def comprehension(n):
    for _ in range(n):
        l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        l = ["A" if i % 2 == 0 else elem for i, elem in enumerate(l)]

start = time.time()
slicing(10000)
print(f'Using slicing and math.ceil: {time.time() - start} seconds')

start = time.time()
comprehension(10000)
print(f'Using list comprehension:    {time.time() - start} seconds')

>>> Using slicing and math.ceil: 0.004003286361694336 seconds
>>> Using list comprehension:    0.012019157409667969 seconds

Edit #2: For anyone wondering, Alain's answer comes in at around 0.0075 seconds per 10,000 loops on average, so basically right in the middle.


Old answer: Try using a list comprehension paired with enumerate:

l = ["A" if i % 2 == 0 else elem for i, elem in enumerate(l)]

This replaces every element with an odd index (odd numbers % 2 will equal 0) with the letter "A", and leaves the remaining elements as they are. Enumerate loops over the original iterable, but includes an index element as well.

You must provide as many elements as there are items to assign:

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

l[::2] = ("A" for _ in l[::2])

print(l)
['A', 1, 'A', 3, 'A', 5, 'A', 7, 'A', 9, 'A']

Or this way:

l[::2] = ["A"]*len(range(0,len(l),2))
Related