reverse list and append it to istelf [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 7 months ago.
Im trying to get a list to inputted in a function, and then the output would be the list, and then the reverse of the list added onto itself but for some reason whenever I reverse the variable reversal, it reverses list as well
def mirror(list):
reversel = list
reversel.reverse()
list.extend(reversel)
return list
test = ["alpha", "beta"]
print(mirror(test))
output
['beta', 'alpha', 'beta', 'alpha']
desired output
["alpha","beta","beta","alpha"]

You can use slicing:
def mirror(lst):
return lst + lst[::-1]
test = ["alpha", "beta"]
print(mirror(test)) # ['alpha', 'beta', 'beta', 'alpha']
An issue in the provided code is that (i) reversel = list (but don't use list as a name) does not copy the object, and (ii) reverse() reverses the list in place. These two lines of code, therefore, reverse the list list (as well as reversel). As a result, now list and reversel both are ["beta", "alpha"]. Then after list.extend(reversel), list becomes what you observe.
Also, there is another subtle issue; it is not generally recommended doing both of the following: (i) modify a given object, and (ii) return the object; this might cause confusion (I believe). It is better to do only one of them; modify an object in place (like reverse), or don't modify the object but return a modified copy of the object (like reversed).

Here is a solution without using reverse().
def mirror(list_to_mirror):
reversel = list_to_mirror
reversel = reversel[::-1]
#This is an equivilant to reverse()
list_to_mirror.extend(reversel)
return list_to_mirror
if __name__ == "__main__":
test = ["alpha", "beta"]
print(mirror(test))

This should work -
def mirror(list):
reversel = [i for i in list]
reversel.reverse()
list.extend(reversel)
return list
test = ["alpha", "beta"]
print(mirror(test))
when using '=' it stores the location of the variable. So when using a function like reverse, both values change.

A way that doesn't require creating and discarding a copy:
def mirror(lst):
lst += reversed(lst)
return lst

Related

How to 'format' a list in python [duplicate]

I'm trying to write a program that removes duplicates from a list, but my program keeps throwing the error "list index out of range" on line 5, if n/(sequence[k]) == 1:. I can't figure this out. Am I right in thinking that the possible values of "k" are 0, 1, and 2? How is "sequence" with any of those as the index outside of the possible index range?
def remove_duplicates(sequence):
new_list = sequence
for n in sequence:
for k in range(len(sequence)):
if n/(sequence[k]) == 1:
new_list.remove(sequence[k])
print new_list
remove_duplicates([1,2,3])
I strongly suggest Akavall's answer:
list(set(your_list))
As to why you get out of range errors: Python passes by reference, that is sequence and new_list still point at the same memory location. Changing new_list also changes sequence.
And finally, you are comparing items with themselves, and then remove them. So basically even if you used a copy of sequence, like:
new_list = list(sequence)
or
new_list = sequence[:]
It would return an empty list.
Your error is concurrent modification of the list:
for k in range(len(sequence)):
if n/(sequence[k]) == 1:
new_list.remove(sequence[k])
It may seem removing from new_list shouldn't effect sequence, but you did new_list = sequence at the beginning of the function. This means new_list actually literally is sequence, perhaps what you meant is new_list=list(sequence), to copy the list?
If you accept that they are the same list, the error is obvious. When you remove items, the length, and the indexes change.
P.S. As mentioned in a comment by #Akavall, all you need is:
sequence=list(set(sequence))
To make sequence contain no dupes. Another option, if you need to preserve ordering, is:
from collections import OrderedDict
sequence=list(OrderedDict.fromkeys(sequence))
If you don't like list(set(your_list)) because it's not guaranteed to preserved order, you could grab the OrderedSet recipe and then do:
from ordered_set import OrderedSet
foo = list("face a dead cabbage")
print foo
print list(set(foo)) # Order might change
print list(OrderedSet(foo)) # Order preserved
# like #Akavall suggested
def remove_duplicates(sequence):
# returns unsorted unique list
return list(set(sequence))
# create a list, if ele from input not in that list, append.
def remove_duplicates(sequence):
lst = []
for i in sequence:
if i not in lst:
lst.append(i)
# returns unsorted unique list
return lst

Python list comprehensions that return multiple lists [duplicate]

This question already has an answer here:
What is the inverse function of zip in python? [duplicate]
(1 answer)
Closed 5 years ago.
I don't know whether it is anyway possible in Python and that is the reason why I ask it here.
I have a Python function that returns a tuple:
def my_func(i):
return i * 2, 'a' * i
This is just a dumb function that given a number k, it returns k * 2 as is and another string is the letter 'a' concatenated k times.
I want now to form two lists, calling the function with i = 0...9, I want to create one list with all the first values and another one with the rest of them.
What I do with my current knowledge is:
Option 1: Run the same list comprehension two times, that is not very efficient:
first_vals = [my_func(i)[0] for i in range(10)]
second_vals = [my_func(i)[1] for i in range(10)]
Option 2: Avoiding list comprehensions:
first_vals = []
second_vals = []
for i in range(10):
f, s = my_func(i)
first_vals.append(f)
second_vals.append(s)
Option 3: Use list comprehension to get a list of tuples and then two other list comprehension to copy the values. It is better than Option 1, as here my_func() is only called once for each i:
ret = [my_func(i) for i in range(10)]
first_vals = [r[0] for r in ret]
second_vals = [r[1] for r in ret]
Is it possible to somehow use the list comprehension feature in order to return two lists in one command and one iteration, assigning each returned parameter into a different list?
Option 4: Use the inverse of zip:
first_vals, second_vals = zip(*[my_func(i) for i in range(10)])
As Mark Dickinson pointed out in the comment this will lead to tuples for first_vals and second_vals. If you need them to be of type list you can, for example, apply a map:
first_vals, second_vals = map(list, zip(*[my_func(i) for i in range(10)]))

Correct sequence of python functions [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 6 years ago.
I wrote a very basic python code, but it didn't work:
str = "asddasdvsatvsyvcstvcsacvsacvsaifteiopvnvbcshavsdsdzasbbnyju"
dict = {}
for i in str:
dict[i] = dict.get(i,0)+1
print(list(dict.items()).sort())
then I just changed the sequence of functions and separated them, and surprisingly it worked!
str = "asddasdvsatvsyvcstvcsacvsacvsaifteiopvnvbcshavsdsdzasbbnyju"
dict = {}
for i in str:
dict[i] = dict.get(i,0)+1
mylist = list(dict.items())
mylist.sort()
print(mylist)
What's happened from my first to second code that makes it work?
list.sort() sorts the list in place but returns None, that's why in the first example you're seeing None printed out.
You could use built-in sorted, that works exactly the same but creates and returns new list.
sort returns nothing. Therefore, print(l.sort()) prints nothing.
However, l.sort(), and therefore print(l.sort()), does sort the l
list.
Therefore, printing l after l.sort() has been executed will print something, namely, the l list sorted.
.sort() sorts the list in-place (it changes the list itself and doesn't make a copy). But it doesn't return anything (other than None).
If you do
print(list(dict.items()).sort())
You print the return value of sort() -- which is None.
But with
mylist.sort()
print(mylist)
You first sort, and then you print the value of mylist. That's what you want.
You could also have done
print(sorted(mylist))
But that leaves mylist unchanged.

Get the length of reversed list [duplicate]

This question already has answers here:
Why does len() not support iterators?
(2 answers)
Closed 7 months ago.
Getting the length of reversed list doesn't work:
lst = [1,2,3]
lst = reversed(lst)
print len(lst)
throws TypeError: object of type 'listreverseiterator' has no len()
A work around is:
lst = [1,2,3]
lst_length = len(lst)
lst = reversed(lst)
print lst_length
# OR
lst = lst[::-1]
print len(lst)
Now my real question is why?
Simply reversing a list does not alter the length of the list,
so why is Python throwing that exception?
The function reversed() returns an iterator, not an actual list.
You cannot directly get the len() of an iterator (see here).
You could instead reverse the list using Extended Slice syntax:
lst_reversed = lst[::-1]
or reverse the list in place:
lst.reverse()
If you must use an iterator you could first turn it into a list:
lst_reversed = list(reversed(lst))
With each of these approaches len() will then work as expected.
reversed doesn't produce new list, it just return iterator object. You can use lst.reverse() - and it doesn't return anything, but make your lst in reversed order
reversed returns iterator so to determine length you have to consume it.
For example rev_len = len(list(reversed(lst))).
FYI list.reverse method reverses a list in place: lst.reverse()
Anyway your reversed list has the same size as the original one, so you can just determine the length even before reversing.

Why doesn't [].extend(list1) create an identical list to list1? [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 5 months ago.
The analogue for strings holds true:
string1 = 'abc'
''.join(string1) == string1 # True
So why doesn't this hold true:
list1 = ['a', 'b', 'c']
[].extend(list1) == list1 # AttributeError: 'NoneType' object has no attribute 'extend'
type([]) returns list. Why would it get perceived as a NoneType instead of a list which would have the extend method?
This is an academic question. I wouldn't do this is regular code, I just want to understand.
Because list.extend() modifies the list in place and does not return the list itself. What you'd need to do to get what you expect is:
lst = ['a', 'b', 'c']
cplst = []
cplst.extend(lst)
cplst == lst
The functions you reference are not really analogous. join() returns a new string created by concatenating the members of an iterator together with the string being joined on. An analogous list operation would look more like:
def JoiningList(list):
def join(self, iterable):
new_list = iterable[0]
for item in iterable[1:]:
new_list.extend(self)
new_list.append(item)
return new_list
Your're trying to compare the return value of the extension to the list. extend is an in-place operation, meaning that it doesn't return anything.
join, on the other hand, actually returns the result of the operation, so it is possible to compare the two strings.
>>> first = [1,2,3]
>>> second = []
>>> second.extend(first)
>>> first == second
True

Categories

Resources