Как перевернуть список с помощью рекурсии в Python?

Я хочу иметь функцию, которая будет возвращать обратный список, который ей задан, используя рекурсию. Как я могу это сделать?


person Community    schedule 19.10.2008    source источник


Ответы (16)


Добавьте первый элемент списка в перевернутый подсписок:

mylist = [1, 2, 3, 4, 5]
backwards = lambda l: (backwards (l[1:]) + l[:1] if l else []) 
print backwards (mylist)
person John Millikin    schedule 19.10.2008

Немного более явно:

def rev(l):
    if len(l) == 0: return []
    return [l[-1]] + rev(l[:-1])

Это превращается в:

def rev(l):
    if not l: return []
    return [l[-1]] + rev(l[:-1])

Что превращается в:

def rev(l):
    return [l[-1]] + rev(l[:-1]) if l else []

Это то же самое, что и другой ответ.


Хвостовой рекурсивный/стиль CPS (который python все равно не оптимизирует):

def rev(l, k):
    if len(l) == 0: return k([])
    def b(res):
        return k([l[-1]] + res)
    return rev(l[:-1],b)


>>> rev([1, 2, 3, 4, 5], lambda x: x)
[5, 4, 3, 2, 1]
person Claudiu    schedule 19.10.2008

Я знаю, что это бесполезный ответ (хотя на этот вопрос уже был дан ответ), но в любом реальном коде, пожалуйста, не делайте этого. Python не может оптимизировать хвостовые вызовы, имеет медленные вызовы функций и имеет фиксированную глубину рекурсии, поэтому есть как минимум 3 причины, по которым вместо этого следует делать это итеративно.

person Community    schedule 19.10.2008
comment
Чтобы не соглашаться с вами по существу, пожалуйста, не делайте этого в реальном коде. В данном конкретном случае не имеет значения, что Python не оптимизирует хвостовые вызовы, потому что реверсия списка не является хвостовой рекурсией без CPS. - person ddaa; 19.10.2008

Хитрость заключается в том, чтобы присоединиться после рекурсии:

def backwards(l):
  if not l:
    return
  x, y = l[0], l[1:]
  return backwards(y) + [x]
person Ignacio Vazquez-Abrams    schedule 19.10.2008

Используйте стратегию «Разделяй и властвуй». Алгоритмы D&C являются рекурсивными алгоритмами. Чтобы решить эту проблему с помощью D&C, необходимо выполнить два шага:

  1. Разберитесь с базовым случаем. Это должен быть самый простой возможный случай.
  2. Разделите или уменьшите свою проблему, пока она не станет базовым случаем.

Шаг 1: Определите базовый вариант. Какой самый простой список вы можете получить? Если вы получаете список с 0 или 1 элементом, это довольно легко подвести итог.

if len(l) == 0:  #base case
    return []

Шаг 2: Вам нужно приближаться к пустому списку с каждым рекурсивным вызовом

recursive(l)    #recursion case

Например

l = [1,2,4,6]
def recursive(l):
    if len(l) == 0:
        return []  # base case
    else:
        return [l.pop()] + recursive(l)  # recusrive case


print recursive(l)

>[6,4,2,1]

Источник: Алгоритмы Grokking

person Community    schedule 18.07.2017

Этот переворачивается на месте. (Конечно, итеративная версия была бы лучше, но она должна быть рекурсивной, не так ли?)

def reverse(l, first=0, last=-1):
    if first >= len(l)/2: return
    l[first], l[last] = l[last], l[first]
    reverse(l, first+1, last-1)

mylist = [1,2,3,4,5]
print mylist
reverse(mylist)
print mylist
person Federico A. Ramponi    schedule 20.10.2008

Рекурсивная функция для обращения списка.

def reverseList(lst):
    #your code here
    if not lst:
        return []
    return [lst[-1]] + reverseList(lst[:-1])


print(reverseList([1, 2, 3, 4, 5]))
person Community    schedule 30.10.2019

выглядит проще:

    def reverse (n):
        if not n: return []
        return [n.pop()]+reverse(n)
person Community    schedule 07.03.2017

Возьмите первый элемент, рекурсивно переверните остальную часть списка и добавьте первый элемент в конец списка.

person JesperE    schedule 19.10.2008

def reverseList(listName,newList = None):
if newList == None:
    newList = []
if len(listName)>0:
    newList.append((listName.pop()))
    return reverseList(listName, newList)
else:
    return newList

напечатать обратный список ([1,2,3,4]) [4,3,2,1]

person Community    schedule 28.02.2016

Использование аргумента Mutable по умолчанию и рекурсии:

def hello(x,d=[]):
    d.append(x[-1])
    if len(x)<=1:
        s="".join(d)
        print(s)

    else:
        return hello(x[:-1])

hello("word")

Дополнительная информация

x[-1]    # last item in the array
x[-2:]   # last two items in the array
x[:-2]   # everything except the last two items

Часть рекурсии - hello(x[:-1]), где функция приветствия снова вызывается после x[:-1]

person Community    schedule 11.10.2016

Это также изменит вложенные списки!

A = [1, 2, [31, 32], 4, [51, [521, [12, 25, [4, 78, 45], 456, [444, 111]],522], 53], 6]

def reverseList(L):

    # Empty list
    if len(L) == 0:
        return

    # List with one element
    if len(L) == 1:

        # Check if that's a list
        if isinstance(L[0], list):
            return [reverseList(L[0])]
        else:
            return L

    # List has more elements
    else:
        # Get the reversed version of first list as well as the first element
        return reverseList(L[1:]) + reverseList(L[:1])

print A
print reverseList(A)

БЛОГ Падмала

person Community    schedule 24.10.2016

Вы можете уменьшить глубину рекурсии вдвое, поменяв местами первый и последний элементы сразу и рекурсивно вызвав rev в середине списка:

lks=[2,7,3,1,9,6,5]
def rev(lks):
    if len(lks)<2:
        return lks
    return [lks[-1]]+rev(lks[1:-1])+[lks[0]]
print(rev(lks))
person Community    schedule 13.06.2021
comment
Это интересный подход, когда два конца одновременно меняются местами. Мне это нравится. - person joanis; 14.06.2021

Ответ, который вы ищете, находится внутри функции. Остальное просто для того, чтобы увидеть (или если вы хотите сравнить) время, затрачиваемое различными алгоритмами.

import time
import sys

sys.setrecursionlimit(10**6)


def reverse(ls1):
    if len(ls1) <= 1:
        return ls1
    else:
        ls1[0], ls1[-1] = ls1[-1], ls1[0]
        return [ls1[0]] + reverse(ls1[1:-1]) + [ls1[-1]]


ls = [*range(2000)]
start_time = time.time()
print(reverse(ls))
stop_time = time.time()
print(f"Total time taken: {(stop_time - start_time) * 1000} msec.")
person Community    schedule 20.06.2021

Почему бы и нет:

a = [1,2,3,4,5]
a = [a[i] for i in xrange(len(a)-1, -1, -1)] # now a is reversed!
person Community    schedule 11.10.2016

если это список чисел, то проще всего его изменить. Это также будет работать для строк, но не рекомендуется.

l1=[1,2,3,4]
l1 = np.array(l1)
assert l1[::-1]==[4,3,2,1]

если вы не хотите сохранять его как массив numpy, вы можете передать его в список как

l1 = [*l1]

опять же, я не рекомендую его для списка строк, но вы могли бы, если бы действительно хотели.

person Community    schedule 22.11.2020