10

I'm using Python 3.5.

As part of a problem, I'm trying to design a function that takes a list as input and reverts it. So if x = [a, b, c] the function would make x = [c, b, a].

The problem is, I'm not allowed to use any built-in functions, and it has got me stuck. My initial thought was the following loop inside a function:

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

And it works. But the problem is I'm using len(x), which I believe is a built-in function, correct?

So I searched around and have made the following very simple code:

y = x[::-1]

Which does exactly what I wanted, but it just seems almost too simple/easy and I'm not sure whether "::" counts as a function.

So I was wondering if anyone had any hints/ideas how to manually design said function? It just seems really hard when you can't use any built-in functions and it has me stuck for quite some time now.

0

11 Answers 11

7

range and len are both built-in functions. Since list methods are accepted, you could do this with insert. It is reeaallyy slow* but it does the job for small lists without using any built-ins:

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

By continuously inserting at the zero-th position you end up with a reversed version of the input list:

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

Doing:

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

could also be considered a solution. ::-1 (:: has a different result) isn't a function (it's a slice) and [] is, again, a list method. Also, contrasting insert, it is faster and way more readable; just make sure you're able to understand and explain it. A nice explanation of how it works can be found in this S.O answer.

*Reeaaalllyyyy slow, see juanpa.arrivillaga's answer for cool plot and append with pop and take a look at in-place reverse on lists as done in Yoav Glazner's answer.

Sign up to request clarification or add additional context in comments.

Comments

1

:: is not a function, it's a python literal. as well as []

How to check if ::, [] are functions or not. Simple,

    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

If ::,[] were functions, you should find a label CALL_FUNCTION among python instructions executed by a[::-1] statement. So, they aren't.

Look how python instructions looks like when you call a function, lets say list() function

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

So, basically

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

works fine. But, I think you should do something like Jim suggested in his answer if your question is a homework or sent by you teacher. But, you can add this quickest way as a side note.

If you teacher complains about [::-1] notation, show him the example I gave you.

Comments

1

Your example that works:

y = x[::-1]

uses Python slices notation which is not a function in the sense that I assume you're requesting. Essentially :: acts as a separator. A more verbose version of your code would be:

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

or

y = x[start:end:step]

I probably wouldn't be complaining that python makes your life really, really easily.


Edit to be super pedantic. Someone could argue that calling [] at all is using an inbuilt python function because it's really syntactical sugar for the method __getitem__().

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

And using :: does make use of the slice() object.

x.__getitem__(slice(len(x), None, -1) == x[::-1]

But... if you were to argue this, anything you write in python would be using inbuilt python functions.

Comments

1

Another way ( just for completeness :) )

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

Comments

1

Here's a solution that doesn't use built-in functions but relies on list methods. It reverse in-place, as implied by your specification:

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

ETA

Jim, your answer using insert at position 0 was driving me nuts! That solution is quadratic time! You can use append and pop with a temporary list to achieve linear time using simple list methods. See (reverse is in blue, rev is green):

If it feels a little bit like "cheating" using seq[:] = temp, we could always loop over temp and append every item into seq and the time complexity would still be linear but probably slower since it isn't using the C-based internals.

1 Comment

Oh yes, reeaaalllyyyy slow. I hate myself too :-)
1

Here's a solution , using no in-built functions (not even len()) just loops

def reverse(L):

    i = 0
    j = -1
    for x in L:
        j+=1
    while i<j:
        L[i],L[j]=L[j],L[i]
        i+=1
        j-=1
    return L

Comments

0

Another way for completeness, range() takes an optional step parameter that will allow you to step backwards through the list:

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

3 Comments

range is a builtin - the OP asked how not to use a builtin
I assumed he meant not using the builtin reversed() or list.reverse() since OP used range() in their example. As another answer also pointed out it's sort impossible to much in Python with out using a built in function since even list[x] calls a built in method of the list.
This answer might also be useful for another person in the future looking for a way to reverse a list without using reversed()/list.reverse()
0

The most pythonic and efficient way to achieve this is by list slicing. And, since you mentioned you do not need any inbuilt function, it completely suffice your requirement. For example:

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

Comments

0

Just iterate the list from right to left to get the items..

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

Comments

0

Without built-in functions

myList = [1,4,7,5,2,3,1]

for i in range(0, len(myList)):
    for j in range(i+1, len(myList)):
        myList[i], myList[j] = myList[j], myList[i]
    
print(myList)

Comments

0

Beautiful answers here, I'd like to add mine without ANY builtin as I just had an interview which required this. Since you don't want to go with the simple list[::-1] option, you can try this also:

def reverse_list(original_list):
    result_list = []
    i = -1
    for _ in original_list:
        result_list.append(original_list[i])
        i -= 1
    return(result_list)

calling the function:

print(reverse_list(['grape', 'banana', 'apple', 'orange', 'papaya', 'mango']))
print(reverse_list([0, 1, 4, 6, 7, 5, 2, 9, 3, 8]))

will output:

['mango', 'papaya', 'orange', 'apple', 'banana', 'grape']
[8, 3, 9, 2, 5, 7, 6, 4, 1, 0]

Do note that the function can also accept a tuple as argument and reverse it appending each item to result_list and finally returns the list.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.