List comprehensions in Python "freezing" Jupyter notebook - python

When I run the code below in Jupyter notebook, my "kernel" freezes (I get an asterisk between the square brackets like so: [*]):
x = [1,2,3,4]
for num in x:
x.append(num**2)
Why doesn't this code "append" the exponentiated numbers to the end of x?
The code below works and I understand why, but why doesn't the code above work:
x = [1,2,3,4]
out = []
for num in x:
out.append(num**2)
print(out)

You are iterating over a list, and in every iteration you append a new element to the list, so the iteration is never going to end.
To see what's happening, change your code to this:
import time
x = [1,2,3,4]
for num in x:
x.append(num**2)
time.sleep(0.5)
print(x)
If you know what you are doing, you can avoid this kind of "dynamic iteration" with the [:] trick:
x = [1,2,3,4]
for num in x[:]:
x.append(num**2)
This way you are iterating over x[:], not the growing x, in effect it's like you are iterating over a snapshot of x.

More concisely, you could use a list comprehension as follows:
x = [1,2,3,4]
x_squared = [elem**2 for elem in x]
x.extend(x_squared)

Related

Need help understanding a specific type of for loop [duplicate]

This question already has answers here:
What does "list comprehension" and similar mean? How does it work and how can I use it?
(5 answers)
Closed 6 months ago.
I am still relatively new to coding. I've been doing this for less than a year and most of the basics I completely understand now. However, every now and then I come across a type of for loop that I can't get my head around.
It usually goes like this:
x for x in list if x in otherList
I completley understand for loops and if statements. But that particular line of code always confuses me. Would anyone be able to provide a detailed explanation of what actually is happening there, please?
It's called a list comprehension if it's in brackets []:
This:
new_list = [x for x in my_list if x in other_list]
Is equivalent to this:
new_list = []
for x in my_list:
if x in other_list:
new_list.append(x)
If it's in parentheses () it's called a generator:
This:
new_list = (x for x in my_list if x in other_list)
Is sort of equivalent to this:
def foo():
for x in my_list:
if x in other_list:
yield x
new_list = foo()
You might want to read this question and answer to understand more about generators and yielding functions.
This is used within a list comprehension and the if statement acts as a filter.
You may begin with a list of all numbers from 0-9:
mynums = range(10)
But then you might want only the even numbers in a new list:
myevennums=[]
for i in mynums:
if mynums%2 ==0:
myevennums.append(i)
That works but so many keystrokes 😭
So python allows list comprehensions:
myevennums = [i for i in mynums if i%2==0]
The condition could be anything, including membership in another list:
evens_to_20 = list(range(0,21,2))
Then you could create a list with the elements of your list that are also in the other list:
myevennums = [i for i in mynums if i in evens_to_20]
In general, when you see a statement like that you can always expand it as:
Y_comprehension = [i for i in X if condition(i)]
# the same as
Y_loop=[]
for i in X:
if condition(i):
Y_loop.append(i)
assert Y_comprehension == Y_loop
If the condition really is very simple, the list-comprehension is usually the better choice. If it starts to get complicated, you probably want the loop or an intermediate function def condition(item): ...

Get Delayed output of a variable

hey I have a Loop That is always running That keeps changing a variable Called X like this
And It keeps running And keeps changing. And I want to get the previous output of the variable. How Can I do this?
while True:
X = X+10
X = X*5
print(X)
You can put them in an array and select the last element of the array
I assume this is what you're looking for when you say previous output of variable. I'd suggest you to also read on loops if you've just started with python. Here's a source
while True:
print(x) #this will print value X after each iteration
x= x+10
x= x*5
The psuedo code:
arr1 = []
infinte loop:
x= x+10
x= x*5
append x to array
print arr1 index current time looping minus one

Apply a lambda function while appending to a list

Imagine a one dimensional array 'inter' and an empty list 'visual_pred'. I want to iterate over all elements in the array and append each element to my list while adding the element with the list's last entry.
My code looks like this:
visual = []
for x in inter:
if x > 0:
visual.append(lambda x: x + visual[-1])
else:
visual.append(visual[-1])
After executing the code all entries in my list 'inter' looks like this:
function __main__.lambda(x)
What is the problem here and how can I challenge it?
What you're doing here is appending the lambda function itself to your list and not the lambda functions output. I don't actually see why you need a lambda here anyway. This does what you want.
visual = []
for x in inter:
if x > 0:
visual.append(x + visual[-1])
else:
visual.append(visual[-1])
As BeanBagTheCat pointed out, you're appending the lambda function itself to your list and not the lambda functions output. You can write the same code by BeanBagTheCat in one line using list-comprehension as follows:
visual = [x + visual[-1] if x > 0 else visual[-1] for x in inter]

an unusual List Comprehensions execution order

I come across a list comprehension that is not quite the same as usual. So I am confused about the list-compresion execution order.
import re
folders = ['train_frames001', 'train_masks002',
'val_frames003','val_masks004', 'test_frames005', 'test_masks006']
folders.sort(key=lambda var:[int(x) if x.isdigit() else x
for x in re.findall(r'[^0-9]|[0-9]+', var)])
print(folders)
#Whether the list compresion part means
#for x in re.findall(r'[^0-9]|[0-9]+', var):
# if x.isdigit():
# int(x)
# else:
# x
I did't find related samples and docs.
I think you are confused between order of if-else.
a = [1,2,3,4,5,6,7,8]
If you want simply square of each number
b = [i**2 for i in a]
# [1,4,9,16,25,36,49,64]
If you want even numbers (if statement in list-comprehension)
c = [i for i in a if i%2==0]
# [2,4,6,8]
If you want to square only even numbers(if-else statement ternary operator)
c = [i**2 if i%2==0 else i for i in a]
# [1,4,3,16,5,36,7,64]
I run the code, and get ['test_frames005', 'test_masks006', 'train_frames001', 'train_masks002', 'val_frames003', 'val_masks004'], I think the result is right.
If you want get result like ['train_frames001', 'train_masks002', 'val_frames003', 'val_masks004', 'test_frames005', 'test_masks006'], which sorted by the end number. Maybe you should change your code like below.
import re
folders = ['train_frames001', 'train_masks002',
'val_frames003', 'val_masks004', 'test_frames005', 'test_masks006']
folders.sort(key=lambda var: [int(x)
for x in re.findall(r'[^0-9]|[0-9]+', var) if x.isdigit()])
print(folders)

Why is my program showing a TypeError?

Every time I run my code I get this error
TypeError: sequence item 0: expected str instance, int found
The error shows up even when I have converted each element in the list to a string. Please help me fix this. The code is
def add_list(list1):
m=0
for x in list1:
m=m+x
return m
def summarize(list2):
list1 = list2
for x in list2:
x = "{}".format(x)
return "The sum of {} is {}.".format("".join(list2), add_list(list1))
summarize([1,2,3])
When you run a for loop over a list of immutable objects like strings or numbers it's actually making what's effectively a copy. It doesn't take the actual element itself out of the list. So that means
for x in list2:
x = "{}".format(x)
Changes nothing, because what happens could be written verbosely like this:
for x in list2:
>>> x = list[0]
x = "{}".format(x)
>>> x = list[1]
x = "{}".format(x)
>>> x = list[2]
x = "{}".format(x)
You constantly change x, but that doesn't do anything to the elements of the list. If you want to loop over the elements of a list you need to do this
for i,x in enumerate(list2):
list[i] = "{}".format(x)
In that format, 'i' will be set to the index of the element that x currently is so you can refer back to the actual position in the list and edit it there, which WILL result in the list itself changing.
Also you can just use str(x) to turn something into a string, it's much cleaner. It also works on any datatype so you can always print something
>>> str([12,1,"abba"])
"[12,1,'abba']"
>>> str(open("I'm a file.txt",'r'))
"<open file 'I'm a file.txt', mode 'r' at 0x0000000002ADC420>"
>>> str(None)
"None"
However I recommend trying some of the other solutions for how to print this, this isn't ideal. I just thought it was valuable for you to understand the error.
I think this is clearer
return "The sum of %s is %s." % (list2, add_list(list1))

Categories

Resources