In the below program, I am trying to add all my "new_list" values into my "fin_list". But append is not working as excpected and is overwriting it with whatever the "new_list"value is in that particular loop.
def all_subsequences(ind, a, new_list, fin_list):
if(ind >= len(a)):
print(new_list)
fin_list.append(new_list)
return
new_list.append(a[ind])
all_subsequences(ind+1, a, new_list, fin_list)
#new_list.remove(new_list[len(new_list)-1])
new_list.pop()
all_subsequences(ind+1, a, new_list, fin_list)
return fin_list
a = [3,1,2]
new_list = []
final_list = []
result = all_subsequences(0, a, new_list, final_list)
print(result)
Here the output at each level is as below
[3, 1, 2], [3, 1], [3, 2], [3], [1, 2], [1], [2], []
Since the last value is an empty list the final list value at the last is as below
[[], [], [], [], [], [], [], []]
Link to python sandbox :-
https://pythonsandbox.com/code/pythonsandbox_u21270_9PqNjYIsl7M85NGf4GBSLLrW_v0.py
I have tried to use extend instead of append inside the base condition but that is not the kind of result i am looking for. I am open to any suggestion to resolve this problem.
When you call fin_list.append(new_list), you are appending the reference of new_list to fin_list instead of copying fin_list. Therefore, when you do new_list.pop() later, if you print fin_list, you will find it's also changed.
The situation can be illustrated by this example:
foo = [1, 2, 3]
bar = []
bar.append(foo)
print(f"bar: {bar}")
# modify foo and you will find that bar is also modified
foo.append(4)
print(f"bar: {bar}")
The simplest way to solve the problem is to use fin_list.append(new_list[:]), which will copy new_list and append the copy to fin_list.
def all_subsequences(ind, a, new_list, fin_list):
if (ind >= len(a)):
print(new_list)
fin_list.append(new_list[:])
return
new_list.append(a[ind])
all_subsequences(ind+1, a, new_list, fin_list)
new_list.pop()
all_subsequences(ind+1, a, new_list, fin_list)
return fin_list
a = [3, 1, 2]
new_list = []
final_list = []
result = all_subsequences(0, a, new_list, final_list)
print(result)
Related
I came across a weird syntactical approach at work today that I couldn't wrap my head around. Let's say I have the following list:
my_list = [[1, 2, 3], [4, 5, 6]]
My objective is to filter each nested list according to some criteria and overwrite the elements of the list in place. So, let's say I want to remove odd numbers from each nested list such that my_list contains lists of even numbers, where the end result would look like this:
[[2], [4, 6]]
If I try to do this using a simple assignment operator, it doesn't work.
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l = [num for num in l if num % 2 == 0]
print(my_list)
Output: [[1, 2, 3], [4, 5, 6]]
However, if I "slice" the list, it provides the expected output.
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l[:] = [num for num in l if num % 2 == 0]
print(my_list)
Output: [[2], [4, 6]]
My original hypothesis was that l was a newly created object that didn't actually point to the corresponding object in the list, but comparing the outputs of id(x[i]), id(l), and id(l[:]) (where i is the index of l in x), I realized that l[:] was the one with the differing id. So, if Python is creating a new object when I assign to l[:] then how does Python know to overwrite the existing object of l? Why does this work? And why doesn't the simple assignment operator l = ... work?
It's subtle.
Snippet one:
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l = [num for num in l if num % 2 == 0]
Why doesn't this work? Because when you do l = , you're only reassigning the variable l, not making any change to its value.
If we write the loop out "manually", it hopefully will become more clear why this strategy fails:
my_list = [[1, 2, 3], [4, 5, 6]]
# iteration 1
l = my_list[0]
l = [num for num in l if num % 2 == 0]
# iteration 2
l = my_list[1]
l = [num for num in l if num % 2 == 0]
Snippet two:
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l[:] = [num for num in l if num % 2 == 0]
Why does this work? Because by using l[:] = , you're actually modifying the value that l references, not just the variable l. Let me elaborate.
Generally speaking, using [:] notation (slice notation) on lists allows one to work with a section of the list.
The simplest use is for getting values out of a list; we can write a[n:k] to get the nth, item n+1st item, etc, up to k-1. For instance:
>>> a = ["a", "very", "fancy", "list"]
>>> print(a[1:3])
['very', 'fancy']
Python also allows use of slice notation on the left-side of a =. In this case, it interprets the notation to mean that we want to update only part of a list. For instance, we can replace "very", "fancy" with "not", "so", "fancy" like so:
>>> print(a)
['a', 'very', 'fancy', 'list']
>>> a[1:3] = ["not", "so", "fancy"]
>>> print(a)
['a', 'not', 'so', 'fancy', 'list']
When using slice syntax, Python also provides some convenient shorthand. Instead of writing [n:k], we can omit n or k or both.
If we omit n, then our slice looks like [:k], and Python understands it to mean "up to k", i.e., the same as [0:k].
If we omit k, then our slice looks like a[n:], and Python understands it to mean "n and after", i.e., the same as a[n:len(a)].
If we omit both, then both rules take place, so a[:] is the same as a[0:len(a)], which is a slice over the entire list.
Examples:
>>> print(a)
['a', 'not', 'so', 'fancy', 'list']
>>> print(a[2:4])
['so', 'fancy']
>>> print(a[:4])
['a', 'not', 'so', 'fancy']
>>> print(a[2:])
['so', 'fancy', 'list']
>>> print(a[:])
['a', 'not', 'so', 'fancy', 'list']
Crucially, this all still applies if we are using our slice on the left-hand side of a =:
>>> print(a)
['a', 'not', 'so', 'fancy', 'list']
>>> a[:4] = ["the", "fanciest"]
>>> print(a)
['the', 'fanciest', 'list']
And using [:] means to replace every item in the list:
>>> print(a)
['the', 'fanciest', 'list']
>>> a[:] = ["something", "completely", "different"]
>>> print(a)
['something', 'completely', 'different']
Okay, so far so good.
They key thing to note is that using slice notation on the left-hand side of a list updates the list in-place. In other words, when I do a[1:3] =, the variable a is never updated; the list that it references is.
We can see this with id(), as you were doing:
>>> print(a)
['something', 'completely', 'different']
>>> print(id(a))
139848671387072
>>> a[1:] = ["truly", "amazing"]
>>> print(a)
['something', 'truly', 'amazing']
>>> print(id(a))
139848671387072
Perhaps more pertinently, this means that if a were a reference to a list within some other object, then using a[:] = will update the list within that object. Like so:
>>> list_of_lists = [ [1, 2], [3, 4], [5, 6] ]
>>> second_list = list_of_lists[1]
>>> print(second_list)
[3, 4]
>>> second_list[1:] = [2, 1, 'boom!']
>>> print(second_list)
[3, 2, 1, 'boom!']
>>> print(list_of_lists)
[[1, 2], [3, 2, 1, 'boom!'], [5, 6]]
Is there anyway to change this list comprehension to normal for loop representation.
result=[[]]
result = [x+[y] for x in result for y in sublist]
Edit:
Here is the full code, which i am trying to understand using loops.
result = [[]]
mainlist = [(1,2,3), (1,2,3)]
print(mainlist)
for sublist in mainlist:
result = [x+[y] for x in result for y in sublist]
print(result)
Output(result):
[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
The output will be out.
x = [] # OP was assigning this constant expression to x.
out = []
for y in sublist:
out.append(x + [y])
This is tricky, because it is essentially not a list comprehension on its own but a for-loop combined with a list comprehension.
result = [[]]
mainlist = [(1,2,3), (1,2,3)]
for sublist in mainlist:
out = []
for x in result:
for y in sublist:
out.append(x+[y])
result = out
print(result)
I'm trying to use list comprehension to replace a for loop for the purpose of improving speed. Being new to list comprehensions, it appears that I do not have a complete grasp of how they work. My intent is to pass a list to a function that is held in memory to complete the processing that needs to be done, then return the list. In this simplified example, it looks like instead of returning the list I want it is returning a list of identical lists. So instead of [1, 2, 3, 4, 5] I get [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]. I looked at the result here but it looks like they had a different problem.
lst1 = [1,2,3,4,5]
k = []
def main():
lst2 = [processfile(x) for x in lst1]
print(lst2)
def processfile(i):
k.append(i)
return(k)
if __name__ == '__main__':
main()
Any help would be greatly appreciated.
If you want to return a list then , you don't need to append the items in the lst1 to k just return i
lst1 = [1,2,3,4,5]
def main():
lst2 = [processfile(x) for x in lst1]
print(lst2)
def processfile(i):
return(i)
if __name__ == '__main__':
main()
Since k is only being used in the process file() function, avoid declaring it in the global scope. I didn't quite understand what you wanted/tried to do, but I hope this example will help you with list comprehension, also, I'd recommend you add 'Python' to the title of your post.
Here I will use list comprehension to add 1 to all items in list1.
lst1 = [1,2,3,4,5]
def main():
lst2 = [add1(item) for item in lst1]
print(lst2)
def add1(num):
return num + 1
if __name__ == '__main__':
main()
Expected output is lst2 = [2,3,4,5,6]
Just
lst2 = [processfile(x) for x in lst1]
will be fine.
In that case you should do like below:
def processfile(i):
return(i)
Given a list of integers:
old_list = [1,1,2,-2,5,2,4,4,-1,-2,5]
I run the following code to get all the integers grouped in a list of lists:
old_list.sort()
new_list = []
for i in old_list:
if new_list == []:
new_list.append([i])
elif new_list[-1][0] == i:
new_list[-1].append(i)
else:
new_list.append([i])
print(new_list)
Returning my desired output:
[[-2, -2], [-1], [1, 1], [2, 2], [4, 4], [5, 5]]
On the one hand I found I could condense the if elif statement using and, while retrieving the same output:
old_list.sort()
new_list = []
for i in old_list:
if new_list and new_list[-1][0] == i:
new_list[-1].append(i)
else:
new_list.append([i])
print(new_list)
On the other hand if I try to remove the new_list and from the if statement the following error arises:
IndexError: list index out of range
Why isn't the if new_list and new_list[-1][0] == i: statement firing the same index error?
Because first you check that new_list is not empty, so at least it has a last element. When you remove this check, since your new_list is initially empty, new_list[-1] is out of range.
Okay, so I have this function that I need to create and I think the code checker is somehow flawed and I tried manage it but my code still seems to fail
def reversecomp(L):
""" assumes L is a list of lists whose elements are ints
Mutates L such that it reverses its elements and also
reverses the order of the int elements in every element of L.
It does not return anything.
"""
if L == []:
return L
elif type(L) == int:
return L
else:
return reversecomp(L[1:]) + [reversecomp(L[0])]
def run_code(L):
return reversecomp(L)
print(L)
The question states that you need to mutate L. Your code must work when you do this:
L = [[0, 1, 2], [1, 2, 3], [3, 2, 1], [10, -10, 100]]
reversecomp(L)
print(L)
Test: run_code([[0, 1, 2], [1, 2, 3]])
Your output:
[[3, 2, 1], [2, 1, 0]]
Correct output:
[[3, 2, 1], [2, 1, 0]]
None
The spec says "It does not return anything"; your program does.
L is a list of lists of ints
Okay, so why are you checking type(L) == int when type(L) == list is always true, per the specification?
Mutates L
You're not mutating L at all; you're returning a new list. Mutating L means doing something like L[...] = xxx.
It does not return anything.
You shouldn't be using the return keyword at all in reversecomp.