3

I want to add 5 to my specific list indices using list comprehension

Input

arr=[0,0,0,0,0]

Output

arr=[0,0,5,5,5]

I tried

[arr[i]+=5 for i in range(2,4)]

but it gives an error.

cs95
  • 379,657
  • 97
  • 704
  • 746
Shashi Tunga
  • 496
  • 1
  • 6
  • 24

4 Answers4

6

Don't use list comprehensions for side effects. The purpose of a list comp is to create a new list. To that end, I believe you can use enumerate + range here -

l, u = 2, 4
arr = [x + 5 if i in range(l, u + 1) else x for i, x in enumerate(arr)]

print(arr)
[0, 0, 5, 5, 5]

In python3, this should be very efficient because in checks on range objects are O(1) time. On python2, it would be faster to perform a boolean check (this is what an in check on range does in python3) -

arr = [x + 5 if l <= i <= u else x for i, x in enumerate(arr)]

However, keep in mind that a for loop would be the most efficient method to use here.

for i in range(l, u + 1):
    arr[i] += 5

print(arr)
[0, 0, 5, 5, 5]

Because,

  1. You only iterate over the indices you need to. Nothing more, nothing less
  2. You make changes in place, rather than creating a new list
cs95
  • 379,657
  • 97
  • 704
  • 746
  • 1
    Answers are getting standards. This is the sort of answers SO expects. – Bharath M Shetty Dec 24 '17 at 07:29
  • `x + 5 if lo <= i <= hi else x`... should be faster than `i in range`... – f5r5e5d Dec 24 '17 at 07:35
  • @f5r5e5d On python2, yes. On python3, it really makes no difference. – cs95 Dec 24 '17 at 07:37
  • 1
    nope, `lo <= i <= hi` is 4x faster on my machine, python 3.6 - both are O(1) though – f5r5e5d Dec 24 '17 at 07:49
  • @f5r5e5d interesting. It's possibly due to the fact that a `range` object is created each time the evaluation is to be done. Since that is a loop invariant, taking it out of the loop might improve its speed. – cs95 Dec 24 '17 at 07:50
2

You can also use addition of lists by slicing them here :

arr[0:2] + [i+5 for i in arr[2:5]]

[0, 0, 5, 5, 5]
Bharath M Shetty
  • 30,075
  • 6
  • 57
  • 108
2

You can also try without for loop something like this:

list_1=[0,0,0,0,0]
b=list(range(2,5))
list(map(lambda x,y:list_1.__setitem__(x,list_1[x]+5),b,list_1))
print(list_1)

output:

[0, 0, 5, 5, 5]
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88
2

Here's a Pythonic way to use a list comprehension to replace some indices. In this case, every index except the 2 first ones:

>>> arr = [0,0,0,0,0]
>>> arr[2:] = [i + 5 for i in arr[2:]]
>>> arr
[0, 0, 5, 5, 5]

Note that arr isn't an array, but a list. With numpy, the operation becomes easier:

>>> import numpy as np
>>> arr = np.array([0, 0, 0, 0, 0])
>>> arr
array([0, 0, 0, 0, 0])
>>> arr[2:] += 5
>>> arr
array([0, 0, 5, 5, 5])

It also works if you have a list of indices:

>>> arr = np.array([0, 0, 0, 0, 0])
>>> arr
array([0, 0, 0, 0, 0])
>>> arr[[2, 3, 4]]
array([0, 0, 0])
>>> arr[[2, 3, 4]] += 5
>>> arr
array([0, 0, 5, 5, 5])
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124