20

I'm supposed to create a function, which input is a list and two numbers, the function reverses the sublist which its place is indicated by the two numbers. for example this is what it's supposed to do:

>>> lst = [1, 2, 3, 4, 5] 
>>> reverse_sublist (lst,0,4) 
>>> lst  [4, 3, 2, 1, 5]

I created a function and it works, but I'm not sure is it's in place. This is my code:

def reverse_sublist(lst,start,end):
    sublist=lst[start:end]
    sublist.reverse()
    lst[start:end]=sublist
    print(lst)
Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
Tam211
  • 723
  • 5
  • 10
  • 27
  • 1
    You can check whether it's in-place by using `id()`. – 2rs2ts Mar 07 '14 at 17:58
  • No, this is not actually inplace as we have to create a temporary list (`sublist`) – Valentin Lorentz Mar 07 '14 at 18:14
  • 3
    "In place" is ambiguous. It might mean, "mutate the input object". It might mean, "use `O(1)` additional memory". The latter is usually called an "in-place algorithm", whereas the former is usually called "reverse the list in place", so the exact wording of your assignment might provide clues. – Steve Jessop Mar 07 '14 at 18:23

14 Answers14

30
def reverse_sublist(lst,start,end):
    lst[start:end] = lst[start:end][::-1]
    return lst
flakes
  • 21,558
  • 8
  • 41
  • 88
2

Partial reverse with no temporary list (replace range with xrange if you use Python 2):

def partial_reverse(list_, from_, to):
    for i in range(0, int((to - from_)/2)):
        (list_[from_+i], list_[to-i]) = (list_[to-i], list_[from_+i])

list_ = [1, 2, 3, 4, 5, 6, 7, 8]
partial_reverse(list_, 3, 7)
print(list_)
Valentin Lorentz
  • 9,556
  • 6
  • 47
  • 69
  • That will give an error if you'll try the even length. For ex. partial_reverse(list_, 2, 7)==[1, 2, 8, 7, 5, 6, 4, 3] – Alex Jan 11 '22 at 13:50
2

Easiest way to reverse a list in a partial or complete manner.

listVar = ['a','b','c','d']
def listReverse(list,start,end):
    while(start<end):
        temp = list[start]
        list[start] = list[end] #Swaping
        list[end]=temp
        start+=1
        end-=1
    print(list)


listReverse(listVar,1,3)

Output : - ['a', 'd', 'c', 'b']

SSG
  • 100
  • 7
  • Note there's no need for a temporary variable, just use a oneliner: `list[start], list[end] = list[end], list[start]` – Ory Band Nov 23 '19 at 14:55
2

Not sure if you have a similar problem as mine, but i needed to reverse a list in place.

The only piece I was missing was [:]

exStr = "String"

def change(var):
  var[:] = var[::-1] # This line here

print(exStr) #"String"
change(exStr)
print(exStr) #"gnirtS"
0

... I'm not sure is it's in place.

...

lst[start:end]=sublist

Yes, it's in place. lst is never rebound, only its object mutated.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
0

Just use a slice:

>>> lst = [1, 2, 3, 4, 5] 
>>> lst[0:len(lst[3::-1])]=lst[3::-1]
>>> lst
[4, 3, 2, 1, 5]

Or, perhaps easier to understand:

>>> lst = [1, 2, 3, 4, 5] 
>>> sl=lst[3::-1]
>>> lst[0:len(sl)]=sl
>>> lst
[4, 3, 2, 1, 5]
dawg
  • 98,345
  • 23
  • 131
  • 206
  • 2
    That can't be what OP wants -- you're destroying indices. You want to do `start = 0` `end = 3` `lst[start:end] = lst[end-1::-1] if start==0 else lst[end-1:start-1:-1]`, which frankly should really be rewritten for readability into the function that OP posted to begin with! – Adam Smith Mar 07 '14 at 17:58
  • 1
    Slicing with a negative stride is Tricky. – Ignacio Vazquez-Abrams Mar 07 '14 at 17:58
  • 1
    @adsmith Mismatch between lack of morning coffee and button trigger finger. Fixed. As Ignacio Vazquez-Abrams states, you have to think a little when slicing with a negative stride. Fingers help. Once you get the right relationship -- works great. – dawg Mar 07 '14 at 18:08
0

lst[::-1] is the idiomatic way to reverse a list in Python, The following show how and that it was in-place:

>>> lst = [1, 2, 3, 4, 5]
>>> id(lst)
12229328
>>> lst[:] = lst[::-1]
>>> lst
[5, 4, 3, 2, 1]
>>> id(lst)
12229328
martineau
  • 119,623
  • 25
  • 170
  • 301
0

Try some crazy slicing, see Explain Python's slice notation and http://docs.python.org/2.3/whatsnew/section-slices.html

x = [1,2,3,4,5,6,7,8]

def sublist_reverse(start_rev, end_rev, lst):
    return lst[:end_rev-1:start_rev-1]+lst[:[end_rev]

print sublist_reverse(0,4,x)

[out]:

[8, 7, 6, 5, 4, 3, 2, 1]
Community
  • 1
  • 1
alvas
  • 115,346
  • 109
  • 446
  • 738
0

I have two ways for in-place reversal, the simple way is to loop through the list half-way, swapping the elements with the respective mirror-elements. By mirror-element I mean (first, last), (2nd, 2nd-last), (3rd, 3rd-last), etc.

def reverse_list(A):
    for i in range(len(A) // 2): # half-way
        A[i], A[len(A) - i - 1] = A[len(A) - i - 1], A[i] #swap
    return A

The other way is similar to the above but using recursion as opposed to a "loop":

def reverse_list(A):
    def rev(A, start, stop):
        A[start], A[stop] = A[stop], A[start] # swap
        if stop - start > 1: # until halfway
            rev(A, start + 1, stop - 1)
        return A

    return rev(A, 0, len(A) - 1)
ProfNandaa
  • 3,210
  • 2
  • 18
  • 19
0

I've conducted a tiny experiment and it seems that any assignment to list slice causes memory allocation:

import resource
resource.setrlimit(resource.RLIMIT_AS, (64 * 1024, 64 * 1024))

try:
    # Python 2
    zrange = xrange
    arr_size = 3 * 1024
except NameError:
    # Python 3
    zrange = range
    arr_size = 4 * 1024

arr = list(zrange(arr_size))

# We could allocate additional 100 integers, so there should be enough free memory
# to allocate a couple of variables for indexes in the statement below
#   additional_memory = list(zrange(100))

# MemoryError is raised here
arr[:] = zrange(arr_size)

So you have to use for loop to reverse a sublist in place.

PS: If you want to repeat this test, you should ensure that setrlimit RLIMIT_AS works fine on your platform. Also arr_size may vary for different python implementations.

0

Two methods in-place and constant memory:

def reverse_swap(arr, start=None, end=None):
    """
    Swap two edge pointers until meeting in the center.
    """

    if start is None:
        start = 0
    if end is None:
        end = len(arr)

    i = start
    j = end - 1
    while i < j:
        arr[i], arr[j] = arr[j], arr[i]
        i += 1
        j -= 1

def reverse_slice(arr, start=None, end=None):
    """
    Use python slice assignment but use a generator on the right-hand-side
    instead of slice notation to prevent allocating another list.
    """

    if start is None:
        start = 0
    if end is None:
        end = len(arr)

    arr[start:end] = (arr[i] for i in range(end - 1, start - 1, -1))
dosentmatter
  • 1,494
  • 1
  • 16
  • 23
0

The simplest way is probably to use slice assignment and reversed():

lst[start:end] = reversed(lst[start:end])

You could also slice and reverse at the same time, however this generally requires either using negative indexes or specially handling the case when start = 0, i.e.:

lst[start:end] = lst[end-len(lst)-1:start-len(lst)-1:-1]

or

 lst[start:end] = lst[end-1::-1] if start == 0 else lst[end-1:start-1:-1]

OTOH, using slicing alone is faster than the reversed() solution.

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
0

Much cleaner way to do this

a = [1,2,3,4,5,6,7,8,9]
i = 2
j = 7
while (i<j):
   a[i],a[j]=a[j],a[i]
   j -= 1
   i += 1
print(a)
-1
lst = [1,2,3,4,5,6,7,8]

Suppose you have to reverse 2nd position to 4th position in place.

lst[2:5] = lst[2:5][::-1]

Output:

[1,2,5,4,3,6,7,8]

Eric Aya
  • 69,473
  • 35
  • 181
  • 253