Lists and Function Arguments - python

>>> def duplicate(l):
... l = l + l
...
>>> l1 = [1, 2, 3]
>>> duplicate(l1)
>>> l1
[1, 2, 3]
I believe the function above duplicates the list. But why is the result not [1, 2, 3, 1, 2, 3]?

Concatenation of two list objects (as you do with l + l) always creates a new list object. In your function you then assign that new list object back to the local variable l, which is independent of the global reference l1. The original list object is not affected because only the contents of the list were copied.
If you wanted to alter the list object in place, you need to extend l with itself:
def duplicate(l):
l.extend(l)
list.extend() copies all elements from the list you pass in and adds them to the end of the list object you called it on. Passing in the list itself is safe; it'll only copy the original elements.
Demo:
>>> def duplicate(l):
... l.extend(l)
...
>>> l1 = [1, 2, 3]
>>> duplicate(l1)
>>> l1
[1, 2, 3, 1, 2, 3]

Related

How to create a list so that when I append a variable the first element gets removed from list after a certain threshold

Let's say I want to create a list. The list need to have a MAX length of 5. The list would operate as such:
list = []
list.append(1)
list = [1]
list.append(2)
list = [1,2]
..
list.append(5)
list = [1,2,3,4,5]
But, when I append another number the first element is removed:
list.append(6)
list = [2,3,4,5,6]
This is super basic and I can't figure this one out.
I don't want to use classes - can this be done with basic functions such as slices?
You could use a collections.deque for this:
>>> import collections
>>> data = collections.deque(maxlen=5)
>>> data.append(1)
>>> data.append(2)
>>> data.append(3)
>>> data.append(4)
>>> data.append(5)
>>> data
deque([1, 2, 3, 4, 5], maxlen=5)
>>> data.append(6)
>>> data
deque([2, 3, 4, 5, 6], maxlen=5)
>>>
Note, this can pretty much work like a list object, however, it does have different performance characteristics, perhaps most importantly, no random access (basically, a linked list of arrays, but it won't have constant-time access like an array-list, which is what a list object is).
However, it is particularly meant for these types of operations, a "double-ended queue", it allows for efficient removal and addition at both ends. A list can only efficiently append and pop, but adding / removing from the beginning will be inefficient.
If you need it to be a list, you can use a slightly different approach to add the items (in-place):
L = []
L[:] = L[-4:] + [1] # [1]
L[:] = L[-4:] + [2] # [1, 2]
L[:] = L[-4:] + [3] # [1, 2, 3]
L[:] = L[-4:] + [4] # [1, 2, 3, 4]
L[:] = L[-4:] + [5] # [1, 2, 3, 4, 5]
L[:] = L[-4:] + [6] # [2, 3, 4, 5, 6]
Which you could place in a function to make it easier to use:
def appendMax(L,maxLen,value): # maxLen > 1
L[:] = L[1-maxLen:] + [value]
L = []
appendMax(L,5,1) # [1]
appendMax(L,5,2) # [1, 2]
appendMax(L,5,3) # [1, 2, 3]
appendMax(L,5,4) # [1, 2, 3, 4]
appendMax(L,5,5) # [1, 2, 3, 4, 5]
appendMax(L,5,6) # [2, 3, 4, 5, 6]
Use deque() from collections. It will hold certain amount of variables, after that it will delete the first item while appending.
If you don't want to use libraries or classes, you can simply create a list with N none values inside it, then loop inside the list to replace the values inside it.

Why set automatically unpacks range, but list doesn`t? How this can be used?

I create list and set with range. Set unpacks range, list doesn`t
>>> my_list = [range(5)]
>>> my_set = set(range(5))
>>> my_list
[range(0, 5)]
>>> my_set
{0, 1, 2, 3, 4}
>>> my_list = [*range(5)]
>>> my_list
[0, 1, 2, 3, 4]
The reason why it doesn't unpack is because my_list is only putting two brackets next to it, if you do that with set it will be the same:
>>> my_set = {range(5)}
{range(0, 5)}
But if you do list(...) it will unpack:
>>> my_set = list(range(5))
[0, 1, 2, 3, 4]
It's because you are explicitly creating a new object with range(5) as an argument. This can be done with lists too.
>>> my_list = list(range(5))
>>> my_list
[0, 1, 2, 3, 4]
In this piece of your code:
>>> my_list = [range(5)]
You are creating a list with one generator as its only value. Remember, Python is a first class language, which makes it possible to do this. You can also do this with a set:
>>> my_set = {range(5)}
>>> my_set
{range(0, 5)}
range function returns class
type(range(5))
<class 'range'>
you are building a list of range objects.if you define
foo = {range(5)}
it will be the set of range objects.
You should do the same for both to got the same behavior
foo = list(range(5))
bar = set(range(5))

Removing duplicates from a list but returning the same list

I need to remove the duplicates from a list but return the same list.
So options like:
return list(set(list))
will not work for me, as it creates a new list instead.
def remove_extras(lst):
for i in lst:
if lst.count(i)>1:
lst.remove(i)
return lst
Here is my code, it works for some cases, but I dont get why it does not work for remove_extras([1,1,1,1]), as it returns [1,1] when the count for 1 should be >1.
You can use slice assignment to replace the contents of the list after you have created a new list. In case order of the result doesn't matter you can use set:
def remove_duplicates(l):
l[:] = set(l)
l = [1, 2, 1, 3, 2, 1]
remove_duplicates(l)
print(l)
Output:
[1, 2, 3]
You can achieve this using OrderedDict which removes the duplicates while maintaining order of the list.
>>> from collections import OrderedDict
>>> itemList = [1, 2, 0, 1, 3, 2]
>>> itemList[:]=OrderedDict.fromkeys(itemList)
>>> itemList
[1, 2, 0, 3]
This has a Runtime : O(N)

Reversing order of a tuple of list

I have a tuple ([1,2,3], [4,5,6]) and I want to reverse the list inside so that it becomes ([3,2,1],[6,5,4]) without having to create a new tuple and adding elements to it. The closest I've gotten is:
my_func(....):
for i in tuple(...):
i = i[::-1]
return tuple(....)
problem is that while i prints out what I want..the tuple was never changed
Tuples are immutable but the objects contained by them can be either mutable or immutable, so if we modify a mutable object contained by the tuple then the change will be reflected at all the references of that object, that includes the tuple as well.
As in this case we've lists, so, all we need to do is to loop over the tuple and call .reverse() on the lists.
>>> t = ([1,2,3], [4,5,6])
>>> for x in t:
... x.reverse()
...
>>> t
([3, 2, 1], [6, 5, 4])
Another example:
>>> x = [1, 2, 3]
>>> t = (x, 'abc')
>>> x.reverse()
>>> t
([3, 2, 1], 'abc')
>>> x
[3, 2, 1]
As frostnational says, tuples are immutable, so you will have to create new ones.
You could do something like this:
>>> a = ([1,2,3],[4,5,6])
>>> b = map(lambda t: reversed(t), a)
>>> for sublist in b:
... for item in sublist:
... print(item)
...
3
2
1
6
5
4

python list appending is not working [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.
I have something similar to:
>>> S=list()
>>> T=[1,2,3]
>>> for t in T:
... print(S.append(t))
The output I am getting is:
...
None
None
None
I expect S contains t. Why this is not working with me ?
list.append() does not return anything. Because it does not return anything, it default to None (that is why when you try print the values, you get None).
It simply appends the item to the given list in place. Observe:
>>> S = list()
>>> T = [1,2,3]
>>> for t in T:
... S.append(t)
>>> print(S)
[1, 2, 3]
Another example:
>>> A = []
>>> for i in [1, 2, 3]:
... A.append(i) # Append the value to a list
... print(A) # Printing the list after appending an item to it
...
[1]
[1, 2]
[1, 2, 3]
. append() is a list method, that does not return a value it alters the list. For example .index() or .count() methods return object values, while .append() alters the object. For example:
T = [1, 2, 3]
T.append(4)
print(T)
Result:
[1, 2, 3, 4]
We can use .append() to change the list S and add elements from the list T. Lists S, and T are two separate objects with two different addresses in the memory. With the function id() you can check that.
T = [1, 2, 3]
print(id(T))
S = list()
print(S)
print(id(S))
for t in T:
S.append(t)
print(S)
print(id(S))
Result:
2476978999688
[]
2476978081224
[1, 2, 3]
2476978081224
If you want to use only two different names (S and T) for the same list, we can write:
print(T)
print(id(T))
S = T
print(S)
print(id(S))
Result:
[1, 2, 3]
2476978999688
[1, 2, 3]
2476978999688

Categories