Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python Modifying slice of list in function

Tags:

python

list

slice

Consider the following piece of code:

def func1(a):
    a[:] = [x**2 for x in a]

a = range(10)
print a  #prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
func1(a[:5])
print a  #also prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

I wish to send a slice of the list a and change it inside the function. My expected output is

[0, 1, 4, 9, 16, 5, 6, 7, 8, 9]

Which way is the idiomatic way to do so?

Thanks!

like image 618
omerbp Avatar asked Feb 20 '17 13:02

omerbp


People also ask

Does slicing modify original list?

No, slicing returns a list which is inside the original list. Not a copied list. But, in your code; there is a function which edits the parameter-list. If you are working with parameters, you must know that changes made at a parameter doesn't effect the original variable you pass into it.

Does a slice of an entire list create a new object?

Slicing lists does not generate copies of the objects in the list; it just copies the references to them. That is the answer to the question as asked.

How do you slice a list within a list Python?

With this operator, one can specify where to start the slicing, where to end, and specify the step. List slicing returns a new list from the existing list. If Lst is a list, then the above expression returns the portion of the list from index Initial to index End, at a step size IndexJump.


2 Answers

If you slice the list, you modify only a copy, so what you want to do doesn't work in the form you want.

But you could pass an optional slice object to func1 and if it's not None, use it to perform the slice assignment (else use [:])

I would do the following (used a lambda to avoid copy/paste of the formula and a generator expression to avoid creating a useless temporary list:

def func1(a,the_slice=None):
    e = lambda y : (x**2 for x in y)
    if the_slice:
        a[the_slice] = e(a[the_slice])
    else:
        a[:] = e(a)

testing:

a = list(range(10))
func1(a)
print(a)
a = list(range(10))
func1(a,slice(5))   # stop at 5
print(a)
a = list(range(10))
func1(a,slice(5,len(a),2))  # start at 5 / stop at the end, stride/step 2
print(a)

result:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 1, 4, 9, 16, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 25, 6, 49, 8, 81]
  • in the first case, the totality of the list was changed
  • in the second case, it only changed the first half.
  • in the third case, it changed the second half, but 1 value out of 2 (stride=2)
like image 186
Jean-François Fabre Avatar answered Sep 27 '22 22:09

Jean-François Fabre


This will work:

a = range(10)

a[:5] = [c**2 for c in a[:5]]
like image 27
zipa Avatar answered Sep 27 '22 22:09

zipa