3

I want to create a list of strings. The Strings should all be the same except for some elements, where they should be different. Doing this I came across a strange behaviour:

x = ['spam', 'spam', 'spam', 'spam', 'spam']
x[1] = 'buzz'
x[2] = 'buzz'
x

Out[35]: ['spam', 'buzz', 'buzz', 'spam', 'spam']

But on the other hand:

y = ['spam'] * 5
y[1:3] = ['buzz']
y
Out[36]: ['spam', 'buzz', 'spam', 'spam']

Can someone pleas tell me what I am doing wrong? Thank you very much for your help!

Benjamin
  • 298
  • 1
  • 12

3 Answers3

3

The assignment:

y = ['spam'] * 5

Will cause y to be a list like this:

['spam', 'spam', 'spam', 'spam', 'spam']

The array slice y[1:3] captures the elements at index 1 and 2, and looks like this:

['spam', 'spam']

Aligning the slice to the array at index 1 (where the slice starts):

['spam', 'spam', 'spam', 'spam', 'spam']  # y
        ['spam', 'spam']                  # y[1:3]

Now, when you make the assignment y[1:3] = ['buzz'], it essentially turns this into the below:

['spam', 'buzz', 'spam', 'spam']
        ['buzz']                  
Tagc
  • 8,736
  • 7
  • 61
  • 114
1

y[1:3] is a slice of the list and you replace this slice with a list composed of a single element.

spam spam spam spam spam
     \       /
      \     /
       \   /
spam    buzz   spam spam

IIUC, what you want to do is replace it with a list of the same size composed of N times the new element (buzz).

You could write

y[1:3] = ['buzz', 'buzz']
# or equivalently
y[1:3] = ['buzz'] * 2

which is equivalent and more efficient than using a loop like this:

for i in [1, 2]:
    y[i] = 'buzz'
# or equivalently
for i in range(1, 3):
    y[i] = 'buzz'

As a sidenote, here's another pitfall. A string is an iterator, so whenever an iterator is expected and you pass a string, the string is iterated over character per character, as a list of one-character strings:

y[1:3] = 'buzz'
print(y)
# ['spam', 'b', 'u', 'z', 'z', 'spam', 'spam', 'spam']

In this case, slice [1:3] is replaced with the iterator you provided, which is 'buzz', treated as ['b', 'u', 'z', 'z'].

Jérôme
  • 13,328
  • 7
  • 56
  • 106
0
y[1:3] = ['buzz']

This is not the same as y[1] = 'buzz' plus y[2] = 'buzz'

Just do a for loop

for i in [1,2..whatever you need to change]:
    y[i] = 'buzz'
Netwave
  • 40,134
  • 6
  • 50
  • 93