Реверс списка без использования встроенных функций

Я использую Python 3.5.

в рамках проблемы я пытаюсь создать функцию, которая принимает список в качестве входных данных и возвращает его. Так что если x = [a, b, c] функция сделает x = [c, b, a].

проблема в том, что мне не разрешено использовать какие-либо встроенные функции, и это заставило меня застрять. Моей первоначальной мыслью был следующий цикл внутри функции:

for revert in range(1, len(x) + 1):
    y.append(x[-revert])

и это работает. Но проблема в том, что я использую len(x), который я считаю встроенной функцией, правильно?

поэтому я искал вокруг и сделал следующий очень простой код:

y = x[::-1]

который делает именно то, что я хотел, но это просто кажется почти слишком простым/легким, и я не уверен, что "::" считается функция.

поэтому мне было интересно, есть ли у кого-нибудь подсказки/идеи, как вручную спроектировать указанную функцию? Это просто кажется очень сложным, когда вы не можете использовать встроенные функции, и я застрял на некоторое время.

8 ответов


range и len как встроенные функции. С list методы принимаются, вы можете сделать это с insert. Это reeaallyy медленно* но он делает работу для маленький списки без использования каких-либо встроенных модулей:

def rev(l):
    r = []
    for i in l:
        r.insert(0, i)
    return r

непрерывно вставляя в нулевое положение, вы получаете обратную версию входного сигнала список:

>>> print(rev([1, 2, 3, 4]))
[4, 3, 2, 1]

делаем:

def rev(l): 
    return l[::-1] 

также можно считать решением. ::-1 (:: имеет другой результат) не является функцией (это срез) и [] это, опять же, метод списка. Кроме того, контрастные insert, это быстрее и читабельнее; просто убедитесь, что вы в состоянии понять и объяснить это. Хорошее объяснение того, как это работает, можно найти В С. О. ответ.

*Reeaaalllyyyy медленно, ознакомиться с juanpa.ответ arrivillaga для прохладного сюжета и append С pop и взгляните на in-place reverse по спискам, как это сделано в ответ Йоав Glazner по.


:: - это не функция, это питон литерал. а также []

Как проверить, если ::, [] функции или нет. Просто,

    import dis
    a = [1,2]
    dis.dis(compile('a[::-1]', '', 'eval'))
      1           0 LOAD_NAME                0 (a)
                  3 LOAD_CONST               0 (None)
                  6 LOAD_CONST               0 (None)
                  9 LOAD_CONST               2 (-1)
                 12 BUILD_SLICE              3
                 15 BINARY_SUBSCR
                 16 RETURN_VALUE

если ::,[] были функции, вы должны найти метку CALL_FUNCTION среди инструкций python, выполняемых a[::-1] заявление. Значит, это не так.

посмотрите, как выглядят инструкции python, когда вы вызываете функцию, скажем list() функции

>>> dis.dis(compile('list()', '', 'eval'))
  1           0 LOAD_NAME                0 (list)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE

так, в основном

def rev(f):
    return f[::-1]

работает нормально. Но, я думаю, вы должны сделать что-то, как Джим предложил в своем ответе, если ваш вопрос домашнее задание или послал вас учитель. Но вы можете добавить этот самый быстрый способ в качестве примечания.

если вы учитель жалуется [::-1] нотация, покажите ему пример, который я вам дал.


другой способ ( просто для полноты картины :) )

def another_reverse(lst):
    new_lst = lst.copy() # make a copy if you don't want to ruin lst...
    new_lst.reverse() # notice! this will reverse it in place
    return new_lst

вот решение, которое не использует встроенный функции но полагается на методы списка. Он обратный на месте, как подразумевается вашей спецификацией:

>>> x = [1,2,3,4]
>>> def reverse(seq):
...   temp = []
...   while seq:
...     temp.append(seq.pop())
...   seq[:] = temp
... 
>>> reverse(x)
>>> x
[4, 3, 2, 1]
>>> 

ПВП

Джим, ваш ответ с помощью insert в позиции 0 сводил меня с ума! Это решение квадратичное время! Вы можете использовать append и pop С временным списком для достижения линейного времени с помощью простых методов списка. Смотри (reverse в синий, rev is зеленый):

если это немного похоже на "обман" с помощью seq[:] = temp, мы всегда можем перебрать temp и добавить каждый элемент в seq и сложность времени по-прежнему будет линейной, но, вероятно, медленнее, поскольку она не использует внутренние элементы на основе C.


ваш пример, который работает:

y = x[::-1]

использует Python нотация срезов что не является функцией в том смысле, в каком я предполагаю, что вы запрашиваете. По существу :: действует как разделитель. Более подробная версия вашего кода будет:

y = x[len(x):None:-1]

или

y = x[start:end:step]

Я, вероятно, не жаловался бы, что python делает вашу жизнь очень, очень легко.


редактировать, чтобы быть супер педантичным. Кто-то может возразить, что зову [] вообще использует встроенную функцию python, потому что это действительно синтаксический сахар для метода __getitem__().

x.__getitem__(0) == x[0]

и с помощью :: делает использование


другой способ для полноты, range() принимает необязательный параметр шага, который позволит вам сделать шаг назад по списку:

def reverse_list(l):
    return [l[i] for i in range(len(l)-1, -1, -1)]

самый питонический и эффективный способ достичь этого-срезать список. И, поскольку вы упомянули, что вам не нужна встроенная функция, этого вполне достаточно для вашего требования. Например:

>>> def reverse_list(list_obj):
...     return list_obj[::-1]
...
>>> reverse_list([1, 3, 5 , 3, 7])
[7, 3, 5, 3, 1]

просто повторите список справа налево, чтобы получить элементы..

a = [1,2,3,4]

def reverse_the_list(a):
   reversed_list = []
   for i in range(0, len(a)):
     reversed_list.append(a[len(a) - i - 1])
   return reversed_list

new_list = reverse_the_list(a)
print new_list