Nested for loops with if/else in python - python

simple situation,
I have the following: When I just have an if statement, it works correctly.
products = [1,2,3,4,5]
orders = [1,2,3,4,5]
for product in products:
for order in orders:
if product == order:
print("in list")
Results:
in list
in list
in list
in list
in list
However when adding an else it doesn't work correctly.
for product in products:
for order in orders:
if product == order:
print("in list")
else:
print("not in")
Results:
in list
not in
not in
not in
not in
not in
How can I fix it?
Any help is appreciated.

The set type is a better choice when you want to check if item is in a unique "list of item", e.g.
Lets consider the case where orders are non-unique and products are unique,
products = [1,2,3,4,5]
orders = set([1,2,3,4,5])
for p in products:
if p in orders:
print(f'product {p} in orders set')
else:
print(f'product {p} not in orders set')
Note: Here we use the f-string where you can print to see which p is in the order set.
Lets go back to the code in the original question, you have 2 lists and you want to iterate through the inner list for every outer list. Instead of calling it products/orders, lets call it outer/inner:
outer = [1,2,3,4,5]
inner = [6,7,8,9,0]
for o in outer:
for i in inner:
print(o, i)
[output]:
1 6
1 7
1 8
1 9
1 0
2 6
2 7
2 8
2 9
2 0
3 6
3 7
3 8
3 9
3 0
4 6
4 7
4 8
4 9
4 0
5 6
5 7
5 8
5 9
5 0
If you have a nested loop, for o in outer for i in inner, you will be iterating through all pairs of items in the outer list then the inner list.
Now lets go back to the if else part, if we are looping through the outer list then the inner list and if you only check on the outer list, with an if but not catching the else, you will not be seeing the results when it doesn't fall into the condition.
You can see this effect by adding the if-else after a print statement on every iteration, e.g.
outer = [1,2,3,4,5]
inner = [6,7,8,9,0]
for o in outer:
for i in inner:
print('printing always', o, i)
if o + 5 == i: # We are checking if outer+5=inner, i.e. 1+5= 6, 2+5=7, etc.
print('printing only when outer+5=inner', o, i)
[out]:
printing always 1 6
printing only when outer+5=inner 1 6
printing always 1 7
printing always 1 8
printing always 1 9
printing always 1 0
printing always 2 6
printing always 2 7
printing only when outer+5=inner 2 7
printing always 2 8
printing always 2 9
printing always 2 0
printing always 3 6
printing always 3 7
printing always 3 8
printing only when outer+5=inner 3 8
printing always 3 9
printing always 3 0
printing always 4 6
printing always 4 7
printing always 4 8
printing always 4 9
printing only when outer+5=inner 4 9
printing always 4 0
printing always 5 6
printing always 5 7
printing always 5 8
printing always 5 9
printing always 5 0
Now, we see that the normal loop print always prints, and if condition prints only when the condition is met.
To check when what is printed with an if and else, you can do something like:
outer = [1,2,3,4,5]
inner = [6,7,8,9,0]
for o in outer:
for i in inner:
print('printing always', o, i)
if o + 5 == i: # We are checking if outer+5=inner, i.e. 1+5= 6, 2+5=7, etc.
print('printing only when outer+5=inner', o, i)
else:
print('printing otherwise', o, i)
print('------------')
[output]:
printing always 1 6
printing only when outer+5=inner 1 6
------------
printing always 1 7
printing otherwise 1 7
------------
printing always 1 8
printing otherwise 1 8
------------
printing always 1 9
printing otherwise 1 9
------------
printing always 1 0
printing otherwise 1 0
------------
printing always 2 6
printing otherwise 2 6
------------
printing always 2 7
printing only when outer+5=inner 2 7
------------
printing always 2 8
printing otherwise 2 8
------------
printing always 2 9
printing otherwise 2 9
------------
printing always 2 0
printing otherwise 2 0
------------
printing always 3 6
printing otherwise 3 6
------------
printing always 3 7
printing otherwise 3 7
------------
printing always 3 8
printing only when outer+5=inner 3 8
------------
printing always 3 9
printing otherwise 3 9
------------
printing always 3 0
printing otherwise 3 0
------------
printing always 4 6
printing otherwise 4 6
------------
printing always 4 7
printing otherwise 4 7
------------
printing always 4 8
printing otherwise 4 8
------------
printing always 4 9
printing only when outer+5=inner 4 9
------------
printing always 4 0
printing otherwise 4 0
------------
printing always 5 6
printing otherwise 5 6
------------
printing always 5 7
printing otherwise 5 7
------------
printing always 5 8
printing otherwise 5 8
------------
printing always 5 9
printing otherwise 5 9
------------
printing always 5 0
printing otherwise 5 0
------------

This is working correctly.
One the first loop its comparing 1 to 1,2,3,4,5 then 2 to 1,2,3,4,5.
So because the if statement is true for at least one item in the loop, it will print every time its true. You don't have an else condition so every time it is not true, it doesn't do anything. The full output would be:
in list
not in
not in
not in
not in
not in
in list
not in
not in
not in
not in
not in
in list
not in
not in
not in
not in
not in
in list
not in
not in
not in
not in
not in
in list

In the second code, the total print statement executed will be 25 ( len(products) * len(orders) ).
You'll still get 5 "in list" in output, because when if statement result false, it'll go to else statement and print "not in".

Related

Printing a number, the same number of times

I would like to create the following pattern:
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
Here is my attempt:
def print_numbers(number):
for i in range(number):
print(i * i)
Now clearly this will return the product of the number with itself. I would like to specify this function to print out the number that many times. So something like print(i) * i which is not correct syntax of course. How would I about doing this?
As mentioned by #Barmar you can convert the number into strings and multiply with same number.
#Ex str(4)*3 = 444 #It will print 3times 4.
def print_numbers(number):
for i in range(number+1):
print((str(i)+" ")*i) #Converted number into string and multiply with the same number.
print_numbers(5)
Output:
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
If you wanted a line space b/w each number you can print like: print((str(i)+" ")*i+"\n") This will give.
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5

list index out of range in calculation of nodal distance

I am working on a small task in which I have to find the distance between two nodes. Each node has X and Y coordinates which can be seen below.
node_number X_coordinate Y_coordinate
0 0 1 0
1 1 1 1
2 2 1 2
3 3 1 3
4 4 0 3
5 5 0 4
6 6 1 4
7 7 2 4
8 8 3 4
9 9 4 4
10 10 4 3
11 11 3 3
12 12 2 3
13 13 2 2
14 14 2 1
15 15 2 0
For the purpose I mentioned above, I wrote below code,
X1_coordinate = df['X_coordinate'].tolist()
Y1_coordinate = df['Y_coordinate'].tolist()
node_number1 = df['node_number'].tolist()
nodal_dist = []
i = 0
for i in range(len(node_number1)):
dist = math.sqrt((X1_coordinate[i+1] - X1_coordinate[i])**2 + (Y1_coordinate[i+1] - Y1_coordinate[i])**2)
nodal_dist.append(dist)
I got the error
list index out of range
Kindly let me know what I am doing wrong and what should I change to get the answer.
Indexing starts at zero, so the last element in the list has an index that is one less than the number of elements in that list. But the len() function gives you the number of elements in the list (in other words, it starts counting at 1), so you want the range of your loop to be len(node_number1) - 1 to avoid an -off-by-one error.
The problems should been in this line
dist = math.sqrt((X1_coordinate[i+1] - X1_coordinate[i])**2 + (Y1_coordinate[i+1] - Y1_coordinate[i])**2)
the X1_coordinate[i+1] and the ] Y1_coordinate[i+1]] go out of range on the last number call.

Number half Pyramid Python

I'm trying to print a half pyramid that stars on the left side in python.
So far, this is my code
for i in range(1,12):
for j in range(12 - i):
print(" ", end = " ")
for j in range(1, i):
print(j, end = " " )
print("\n")
and my output is
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
However, my output is meant to be in the opposite order:
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
How can I make this change?
Just reverse the second loop -- the one that prints that actual numbers:
for j in range(i-1, 0, -1):
The last parameter controls the "step", or how much the variable changes on each loop iteration. Output:
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
...
Reverse the range by adding the third argument (-1). Also format your numbers to use 2 places, so 10 is not pushing the last line to the right. Finally, the last print should probably not have \n, since that is already the default ending character of print:
for i in range(1,12):
for j in range(12 - i):
print(" ", end = "")
for j in range(i-1, 0,-1):
print(str(j).rjust(2), end = "" )
print()
You could just reverse the range that you print out as numbers
for i in range(1,12):
for j in range(12 - i):
print(" ", end = " ")
for j in reversed(range(1, i)):
print(j, end = " " )
print("\n")
The problem is in your second for loop, as you are looping from 1 to i, meaning you start off with 1 being printed first, and every following number until (not including) i.
Fortunately, for loops are able to go in reverse. So, instead of:
for j in range(1, i)
You could write:
for j in range((i-1), 0, -1)
Where the first parameter is signifies where the loop starts, the second is where the loop finishes, and the third signifies how large our jumps are going to be, in this case negative. The reason we are starting at i-1 and finishing at 0 is because loops start at exactly the first given number, and loop until just before the second given number, so in your given code the loop stops just before i, and so this one starts just before i as well, although you could remove the -1 if you wish to include 12 in the pyramid.

Empty list index error

I wrote the following two functions:
def place_walls(level):
wall_cords = level[2].split("\n")
for cord in wall_cords:
process_coordinate(cord)
def process_coordinate(coordinate):
cords = coordinate.split()
print cords[0]
Python returns a list index out of range error. If I print the cords variable without an index it prints all the cords in a list, however the last list is an empty list. Might that be the problem, how could that be solved?
The input level looks like this:
1 0
0 0=r=3 3
4 3
5 3
6 3
7 3
8 3
9 3
10 3
11 3
3 4
Assuming it is just the last, empty list you have a problem with: clearly, there is no 1st element to print in that case, so wrap it in an if statement (for example if len(cords)>0:; if the list is empty, do whatever is more appropriate for that circumstance.

Listing distributions in Python

I have a sheet of numbers, separated by spaces into columns. Each column represents a different category, and within each column, each number represents a different value. For example, column number four represents age, and within the column, the number 5 represents an age of 44-55. Obviously, each row is a different person's record. I'd like to use a Python script to search through the the sheet, and find all columns where the sixth column is number "1." After that, I want to know how many times each number in column one appears where the number in column six is equal to "1." The script should output to the user that "While column six equals '1', the value '1' appears 12 times in column one. The value '2' appears 18 times..." etc. I hope I'm being clear here. I just want it to list the numbers, basically. Anyway, I'm new to Python. I've attached my code below. I think I should be using dictionaries, but I'm just not totally sure how. So far, I haven't really come close to figuring this out. I would really appreciate if someone could walk me through the logic that would be behind such code. Thank you so much!
ldata = open("list.data", "r")
income_dist = {}
for line in ldata:
linelist = line.strip().split(" ")
key_income_dist = linelist[6]
if key_income_dist in income_dist:
income_dist[key_income_dist] = 1 + income_dist[key_income_dist]
else:
income_dist[key_income_dist] = 1
ldata.close()
print value_no_occupations
First, indentation is majorly important in Python and the above is bad: the 5 lines following linelist = line.strip().split(" ") need to be indented to be in the loop like they should be.
Next they should be indented further and this line added before them:
if len(linelist)>6 and linelist[6]=="1":
This line skips over short lines (there are some), and tests for what you said you wanted: "where column six equals "1."" This is column [6] where the first number on the line is referenced as [0] (these are "offsets", not "cardinal", or counting, numbers).
You'll probably want to change key_income_dist = linelist[6] to key_income_dist = linelist[0] or [1] to get what you want. Play around if necessary.
Finally, you should say print income_dist at the end to get a look at your results. If you want fancier output, study up on formatting.
This is actually easier than it seems! The key is collections.Counter
from collections import Counter
ldata = open("list.data")
rows = [tuple(row.split()) for row in ldata if row.split()[5]==1]
# warning this will break if some rows are shorter than 6 columns
first_col = Counter(item[0] for item in rows)
If you want the distribution of every column (not just the first) do:
distribution = {column: Counter(item[column] for item in rows) for column in range(len(rows[0]))}
# warning this will break if all rows are not the same size!
Considering that the data file has ~9000 rows of data, if you don't want to keep the original data, you can combine step 1 & 2 to make the program use less memory and a little faster.
ldata = open("list.data", "r")
# read in all the rows, note that the list values are strings instead of integers
# keep only the rows with 6th column = '1'
only1 = []
for line in ldata:
if line.strip() == '': # ignor blank lines
continue
row = tuple(line.strip().split(" "))
if row[5] == '1':
only1.append(row)
ldata.close()
# tally the statistics
income_dist = {}
for row in only1:
if row[0] in income_dist:
income_dist[row[0]] += 1
else:
income_dist[row[0]] = 1
# print result
print "While column six equals '1',"
for num in sorted(income_dist):
print "the value %s appears %d times in column one." % (num, income_dist[num])
Sample Test Data in list.data:
9 2 1 5 4 5 5 3 3 0 1 1 7 NA
9 1 1 5 5 5 5 3 5 2 1 1 7 1
9 2 1 3 5 1 5 2 3 1 2 3 7 1
1 2 5 1 2 6 5 1 4 2 3 1 7 1
1 2 5 1 2 6 3 1 4 2 3 1 7 1
8 1 1 6 4 8 5 3 2 0 1 1 7 1
1 1 5 2 3 9 4 1 3 1 2 3 7 1
6 1 3 3 4 1 5 1 1 0 2 3 7 1
2 1 1 6 3 8 5 3 3 0 2 3 7 1
4 1 1 7 4 8 4 3 2 0 2 3 7 1
1 1 5 2 4 1 5 1 1 0 2 3 7 1
4 2 2 2 3 2 5 1 2 0 1 1 5 1
8 2 1 3 6 6 2 2 4 2 1 1 7 1
7 2 1 5 3 5 5 3 4 0 2 1 7 1
1 1 5 2 3 9 4 1 3 1 2 3 7 1
6 1 3 3 4 1 5 1 1 0 2 3 7 1
2 1 1 6 3 8 5 3 3 0 2 3 7 1
4 1 1 7 4 8 4 3 2 0 2 3 7 1
1 1 5 2 4 9 5 1 1 0 2 3 7 1
4 2 2 2 3 2 5 1 2 0 1 1 5 1
Following your original program logic, I come up with this version:
ldata = open("list.data", "r")
# read in all the rows, note that the list values are strings instead of integers
linelist = []
for line in ldata:
linelist.append(tuple(line.strip().split(" ")))
ldata.close()
# keep only the rows with 6th column = '1'
only1 = []
for row in linelist:
if row[5] == '1':
only1.append(row)
# tally the statistics
income_dist = {}
for row in only1:
if row[0] in income_dist:
income_dist[row[0]] += 1
else:
income_dist[row[0]] = 1
# print result
print "While column six equals '1',"
for num in sorted(income_dist):
print "the value %s appears %d times in column one." % (num, income_dist[num])

Categories

Resources