0

Given the below examples:

array = [1,2,3,4,0]

In: array[0] += 2 
Out: 3

In: array[1:3] += 2  
Out: TypeError: 'int' object is not iterable

In: array[1:3] += [100, 100] 
Out: [1, 2, 3, 100, 100, 4, 5]

Can someone explain me why the two last examples wont return something like [1,102,103,4,0] AND if it is possible doing this with a simple slice, not using a for loop...

Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85
  • 1
    Terminology nitpick: `array[0] += 2 (returns 3)` no it doesn't. It doesn't *return anything*. `x += y` is a statement, it doesn't evaluate to any value. – juanpa.arrivillaga Sep 17 '20 at 20:33
  • For the second case - thats because you are trying to concatenate `list` and `int` – Yossi Levi Sep 17 '20 at 20:33
  • This is not possible using lists. Use numpy arrays instead: `import numpy as np`; `array = np.array([1,2,3,4,0] )` – mathfux Sep 17 '20 at 20:35
  • Anyway, Python list objects do not implement "vectorized" operations like that. – juanpa.arrivillaga Sep 17 '20 at 20:36
  • 1
    @mathfux Not necessarily. It (Adding list slices) can be done in pure python, albeit awkwardly. There's a question with a whole host of different answers (some numpy, some not) here. https://stackoverflow.com/questions/18713321/element-wise-addition-of-2-lists | As for adding 1 int to each element in arrays, yes I assume you'd want numpy or to write your own function. – Allister Sep 17 '20 at 20:36
  • @Allister You're right, this can be done for smth that is not a classical situation where `+` operator is being used on `lists`. But personally, I used to think that `array` is a reference to `np.array`. – mathfux Sep 17 '20 at 20:41

2 Answers2

1

When using the slice operator it refers to sub-part of the list, so operating on it requires a list too (we can use the "add" operator on list with list, and not with an int, unlike in some other languages).

Therefore the following:

array[1:3] += 2

Throws:

TypeError: 'int' object is not iterable

Because 2 is not a list (actually an iterable, which is more general than list).

But:

array[1:3] += [100, 100]

Works and adds (actually appends) the two elements in the middle (index 3) of array according to indexes:

[3, 2, 3, 100, 100, 4, 0]

Without using a for loop, as requested

If you want to add to the values in the slice:

array = [1,2,3,4,0]

array.__setitem__(slice(1, 3), [x+2 for x in array[1:3]])

# [1, 102, 103, 4, 0]
print(array)

Which can be written also as:

array = [1,2,3,4,0]

def apply_on_slice(lst, start, end, callable):
    array.__setitem__(slice(start, end), [callable(x) for x in array[start:end]])

apply_on_slice(array, 1, 3, lambda x : x + 100)

# [1, 102, 103, 4, 0]
print(array)

Using a for loop

Here are some other options to do so, elegantly:

array[1:3] = (x+2 for x in array[1:3])

Or of course, using a regular for loop, which is more efficient than using slicing twice:

for i in range(1, 3): 
    array[i] += 2
Aviv Yaniv
  • 6,188
  • 3
  • 7
  • 22
  • Entirely unnecessary to call the `__setitem__` method explicitly. Just write `array[1:3] = (x+2 for x in array[1:3])`. Or better yet, don't use slicing at all since a simple loop will do it more efficiently: `for i in range(1, 3): array[i] += 2`. – blhsing Sep 17 '20 at 21:07
  • I couldn't agree more, but OP asked explicitly "without for loop". However, I'll add these options as well. Thank you for the comment. @blhsing – Aviv Yaniv Sep 17 '20 at 21:14
0

You are clearly expecting the operation to be applied element-wise, as in R and other languages (and within Python, in numpy arrays and the like). E.g., adding 2 to a list would add 2 to each of the list's elements. This is not how Python lists work: Each of the statements you ask about constructs one object on each side of the operator (a list or list slice, a list element, an integer), then applies the operation (just once) to these two objects. So if you "add" two lists you get concatenation, if you try to add a list and an int you get a TypeError, etc. The details you can read in @Aviv's answer.

alexis
  • 48,685
  • 16
  • 101
  • 161