<jupyter_start><jupyter_text>While loop<jupyter_code># While loop works like this:-

#while(condition):
#    write the operation to be performed
#    write whatever we want here
#    write whatever we want here
# With the while loop we can execute a set of statements as
# long as a condition is true !!

# This would work as an example :-

print("In which year did India get independence?")
year = int(input())

if (year==1947):
    print("Congratulations! You've given the right answer.")
else:
    print("Come on, don't you know this being in India?")
    print("Nothing much to worry about as you have another attempt!")
    print("In which year did India get independence?")
    year = int(input())
    
    if (year==1947):
        print("You got it right this time.")
    else:
        print("Failed in second attempt too..")

# this code runs only for two attempts.<jupyter_output>In which year did India get independence?
2020
Come on, don't you know this being in India?
Nothing much to worry about as you have another attempt!
In which year did India get independence?
1947
You got it right this time.<jupyter_text>We can write a code that let's us attempt as many times as we want until we get right answer.<jupyter_code>print("In which year did India get independence?")
year = int(input())

# I would like to write a code,which lets the user attempt as many times
# as he wants and ends only when it gets the right answer.

while(year!= 1947):
    print("You got this wrong.Enter once again.")
    year = int(input())
    
print("Wonderful you made it right")<jupyter_output>In which year did India get independence?
1940
You got this wrong.Enter once again.
1947
Wonderful you made it right<jupyter_text>An example for while loop<jupyter_code>i = 1
while i < 6:
  print(i)
  i += 1
# Note: Remember to increment i, else the loop will continue forever.<jupyter_output>1
2
3
4
5<jupyter_text>Find the factorial using while loop<jupyter_code>print("Enter a number")
n = int(input())

# if n = 5, then factorial of 5 would be 1*2*3*4*5
i = 1
answer = 1
while (i<=n): # less than or equal to
    answer = answer*i
    i = i+1
    
print(answer)

# i =1
# answer = 1
# n = 5
# answer = 1
# As we increment i by 1 at end of a loop, i has the value 2
# i = 2
# answer = 2
# i = 3
# answer = 6
# i = 4
# answer = 24
# i = 5 
# answer = 120
# i = 6 and this does ot execute as 6 is not less than 5.
# we print last updated value of 'answer'.
# We can use the above code for any integer input or value.
print("Enter a number")
n = int(input())

i = 1
answer = 1
while (i<=n): # less than or equal to
    answer = answer*i
    i = i+1
    
print(answer)<jupyter_output>Enter a number
10
3628800<jupyter_text>Tutorial On While Loop<jupyter_code>num = int(input())
fact = 1 
# we initialize 'fact' with 1 since the factorial of 0 is 1.
if (num <0):
    print("Not defined")
# we cannot print the factorial of negative numbers when num is positive.
else:
    while (num>0):
        fact = fact*num
        num = num -1
# we reduce the value of 'num' as factorial of a number is n*n-1*n-2*...
    print(fact)<jupyter_output>5
120<jupyter_text>Find the number of digits in a given number<jupyter_code># The number of digits are not dependent on sign of the number.
# Can be a +ve or a -ve number.
# we can ignore the sign of a number using absolute function (abs)
num = abs(int(input("Enter a number: ")))
digits = 1
# A number does have 1 digit in the minimum possible range.
while(num>9):
    num = num // 10
    digits = digits + 1
print(digits)<jupyter_output>Enter a number: 1234
4<jupyter_text>Reverse the digits in the given number.<jupyter_code># If the input is 1234, then we need to get the output as 4321.
num = int(input("Enter a number :  "))
absNum = abs(num)

# abs function is used to consider negative numbers as positive.

if (num>0):

# if number is positive

    rev = num % 10
    # we use the modulo operator here in order to get the last digit.
    num = num // 10
    while (num > 0):
    # we use a variable 'r' to get the next last digit.('3' in this case.)
        r = num % 10 # we store 3 here.
        num = num // 10
        rev = rev*10 + r
    # this while loop runs for 3 times since the number got reduced to 123.
    print(rev)

# if number is negative use absNum in place of num
else:
    rev = absNum % 10
    
    # we use the modulo operator here in order to get the last digit.
    
    absNum = absNum // 10
    while (absNum > 0):
    # we use a variable 'r' to get the next last digit.('3' in this case.)
        r = absNum % 10 # we store 3 here.
        absNum = absNum // 10
        rev = rev*10 + r
    # this while loop runs for 3 times since the number got reduced to 123.
    print(rev - 2*rev)
# we can write the above code in a few lines which saves time.

num = int(input("Enter a number :  "))
absNum = abs(num)
rev = absNum % 10
absNum = absNum // 10
while (absNum > 0):
    r = absNum % 10 
    absNum = absNum // 10
    rev = rev*10 + r
# Now the result will be printed according to nature of number.
if(num >= 0):
    print(rev)
else:
    print(rev - 2*rev)<jupyter_output>Enter a number :  -1234
-4321<jupyter_text>Find whether the entered number is a Palindrome ?<jupyter_code># Palindrome number is a special type of number which is
# exactly equal to its original before reversing the digits.

# 12321 , 121 , -1221 are some examples.

num = int(input("Enter a number :  "))
absNum = abs(num)
rev = absNum % 10
absNum = absNum // 10
while (absNum > 0):
    r = absNum % 10 
    absNum = absNum // 10
    rev = rev*10 + r
if(num <0):
    rev = rev-2*rev
    
if(num == rev):
    print("Palindrome")
else:
    print("Not a Palindrome")<jupyter_output>Enter a number :  -1221
Palindrome<jupyter_text>For Loop<jupyter_code>#  for loop is very useful in saving time and getting the result
# that we wanted to get.

# if we want to print "All the Best" 5 times, then:

print("All the Best")
print("All the Best")
print("All the Best")
print("All the Best")
print("All the Best")


# this is where the for loop can do us some help.

for i in range(5):
    print(i,"All the Best")
# we can declare some conditions to be passed to execute for loop.
print("Enter a number :")
n = int(input())

for i in range(n):
    if(i%2 == 0):
        print(i,"All the Best")
    else:
        print(i,"Better luck next time")<jupyter_output>Enter a number :
6
0 All the Best
1 Better luck next time
2 All the Best
3 Better luck next time
4 All the Best
5 Better luck next time<jupyter_text>Add first n numbers<jupyter_code># Assume that we need sum of first 10 integers.
# sum = 1+2+3+4+5+6+7+8+9 = 45
'''
ans = 0+1+2+3+4+5+6+7+8+9
print(ans)

# n could be any (not only 10).'''

print("Enter a number : ")
n = int(input())

ans = 0
for i in range(10):
    ans = ans+ i
print(ans)
    
# ans = 0
# ans = ans + 0, the value is 0
# ans = ans + 1, the value is 1
# ans = ans + 2, the value is 3
# ans = ans + 3, the value is 6
# ans = ans + 4, the value is 10
# ans = ans + 5, the value is 15
# ans = ans + 6, the value is 21
# ans = ans + 7, the value is 28
# ans = ans + 8, the value is 36
# ans = ans + 9, the value is 45<jupyter_output>Enter a number : 
10
45<jupyter_text>For loop for multiplication tables<jupyter_code>'''
General approach:-
print("2 X 1 = 2")
print("2 X 2 = 4")
print("2 X 3 = 6")
print("2 X 4 = 8")
print("2 X 5 = 10")
print("2 X 6 = 12")
print("2 X 7 = 14")
print("2 X 8 = 16")
print("2 X 9 = 18")
print("2 X 10 = 20")
'''

for i in range(10):
    print("2 X", i, "=", 2*i)
# in the above result, we're getting the 2 X 0 = 0 due to
# range function. In general range starts from 0 and ends before (n-1).
# To eliminate 2 X 0 = 0, we can change the range function accordingly.

for i in range(1,11):
    print("2 X", i, "=", 2*i)<jupyter_output>2 X 1 = 2
2 X 2 = 4
2 X 3 = 6
2 X 4 = 8
2 X 5 = 10
2 X 6 = 12
2 X 7 = 14
2 X 8 = 16
2 X 9 = 18
2 X 10 = 20<jupyter_text>More on Range and Variation in For loop<jupyter_code># if we want to print the odd numbers between 1 to 10,
# it can be done using range function.

for x in range(1,11):
    if(x % 2 != 0):
        print(x)
# printing odd numbers without using the inner if loop.

# we add one more parameter called step which acts a difference between
# two numbers.

# range(1,11,2)
# 1 -> start value
# 11 -> end value
# 2 -> step 

for x in range(1,11,2):
    print(x)
# In the above example we had printed the odd numbers between 1 to 10
# in ascending order using step value.

# we can get the odd numbers between 1 and 10 in a descending order also.

# For that to happen we need some changes in range parameters.

for x in range(9,0,-2):
    print(x)<jupyter_output>9
7
5
3
1<jupyter_text>For loop without range<jupyter_code># there's is a way to use for loop without range which is sometimes
# called as 'for each'.

# let's try that with an example.

Subject = "Python"
for letter in Subject:
    print(letter)
# this particular for loop goes through the entire string stored in
# Subject which is a variable, character by character.

#this code is similar to the below print statements.

print(Subject[0])
print(Subject[1])
print(Subject[2])
print(Subject[3])
print(Subject[4])
print(Subject[5])<jupyter_output>P
y
t
h
o
n<jupyter_text>More on Print Statement<jupyter_code>for x in range(10):
    print(x)<jupyter_output>0
1
2
3
4
5
6
7
8
9<jupyter_text>end parameter<jupyter_code># How do we stop printing in a new line? Is that possible ?
# Let's check that now !!

# It is possible to print all the output in a single line using 'end'.

for x in range(11):
    print(x, end = ' ')<jupyter_output>0 1 2 3 4 5 6 7 8 9 10<jupyter_text>sep parameter<jupyter_code># Assume we want to print the Independence Day's Date.
# 15/8/1947

d = 15
m = 8
y = 1947
print("India got Independence on", d, m, y)

# we see that the date doesn't have either - or /.
# Spaces are being added due to a parameter called 'sep' and the default value of 'sep' is space.
# we can over-write the value of 'sep' with one we want to have in place of a space.

d = 15
m = 8
y = 1947
print("India got Independence on", d, m, y, sep = '/')
# Still there's an error as we have a '/' between on and 10.
# Simply we can write a new print statement with d,m,y by specifying seperator.

d = 15
m = 8
y = 1947
print("India got Independence on", end = ' ')
print(d, m, y, sep = '/')<jupyter_output>India got Independence on 15/8/1947<jupyter_text>Formatted Printing<jupyter_code># we can print the multiples of a number using one of the codes above.
# this is a general approach

num = int(input())
for i in range(1,11):
    print(num, 'X', i, '=', num*i)
# We can print the same using a variant in easier manner.

num = int(input())
for i in range(1,11):
    #print(num, 'X', i, '=', num*i)
    print(f'{num} X {i} = {num * i}')

# this is called as formatted printing.
# In the commented line, we have 3 integers and 2 strings
# The entire {num} X {i} = {num * i} is considered to be a single string.<jupyter_output>5
5 X 1 = 5
5 X 2 = 10
5 X 3 = 15
5 X 4 = 20
5 X 5 = 25
5 X 6 = 30
5 X 7 = 35
5 X 8 = 40
5 X 9 = 45
5 X 10 = 50<jupyter_text>Format function of print statement<jupyter_code># format function is denoted and used in python as '.format()'

num = int(input())
for i in range(1,11):
    #print(num, 'X', i, '=', num*i)
    #print(f'{num} X {i} = {num * i}')
    print('{0} X {1} = {2}'.format(num, i, num*i))
    
# Acc. to format function num, i, num*i correspond to 0,1 & 2 respectively.<jupyter_output>5
5 X 1 = 5
5 X 2 = 10
5 X 3 = 15
5 X 4 = 20
5 X 5 = 25
5 X 6 = 30
5 X 7 = 35
5 X 8 = 40
5 X 9 = 45
5 X 10 = 50<jupyter_text>An old way of printing<jupyter_code># we use %d here

num = int(input())
for i in range(1,11):
    #print(num, 'X', i, '=', num*i)
    #print(f'{num} X {i} = {num * i}')
    #print('{0} X {1} = {2}'.format(num, i, num*i))
    print('%d X %d = %d' % (num, i, num*i))
    
# this works the same like format function.

# Let's see if all the formats give the same output.

pi = 22/7
print(f'value of PI = {pi}')
print('Value of PI = {0}'.format(pi))
print('Value of PI = %f' % (pi))

# The last method of printing has some limitations as it is an old method.
# We feel happy with the value of pi as 3.14 for faster calculations.
# The value of 'pi' can be reduced to 3.14 using format specifiers

pi = 22/7
print(f'value of PI = {pi:.2f}')
print('Value of PI = {0:.2f}'.format(pi))
print('Value of PI = %.2f' % (pi))

# format specifier is very useful in order to display the output in a specific manner.
# We can also print some patterns using format specifiers.

print('{0}'.format(1))
print('{0}'.format(11))
print('{0}'.format(111))
print('{0}'.format(1111))
print('{0}'.format(11111))
# this pattern is aligned to the left hand side.
# To print the same pattern aligned to the right. It is easily possible to do by adding spaces.
# But that becomes a tedius process if it was a long pattern.
# Let's see how we can counter this with ease. We see that the max. length is 0f 5 1's.
# We can give 5d after 0 before format parameter which indicates the computer that we
# want to use min. 5 characters in print statement.

print('{0:5d}'.format(1))
print('{0:5d}'.format(11))
print('{0:5d}'.format(111))
print('{0:5d}'.format(1111))
print('{0:5d}'.format(11111))<jupyter_output>1
   11
  111
 1111
11111<jupyter_text>More on For Loop<jupyter_code>''' Let's discuss examples which are used for while loop for a better understanding'''
'''Problem 1 : Find the factorial of given number'''

num = int(input())
fact = 1
if(num < 0):
    print("Not defined")
else:
    for i in range(num, 1, -1):
        fact = fact * i
    print(fact)
#In while loop there's a line for reducing the number by 1 which is num = num -1.
#In this case we dont need that as the range function is having a step of -1.<jupyter_output>5
120<jupyter_text>How to decide which loop is more ideal for a particular code. ( Factors) 1) For loop is to be used if we know the range of the loop. ( loop runs for n number of times ) 2) While loop is to be used if we do not know the range of loop  For loop requires the range function which has the start and end points. So it is mandatory to know the range of iterations.<jupyter_code>''' Problem 2 : Find the number of digits in given number '''

num = abs(int(input("Enter a number: ")))
digits = 1
# A number does have 1 digit in the minimum possible range.
while(num>9):
    num = num // 10
    digits = digits + 1
print(digits)
    
# The number of iterations cannot be predicted because the number entered by user can be a single digit or it can have n digits.
# Hence we cannot predict how many times this loop gets iterated and therefore we use while loop.
# In such a case it is not possible to convert this into an equivalent for loop code.
''' Solving Problem 2 with for each approach '''

# This is not an ideal code, but is possible to build one using 2nd approach of for loop.

num = abs(int(input()))
strNum = str(num) # we convert the given number into a string.
digits = 0
for c in strNum:
    digits = digits + 1
print(digits)
''' Problem 3 : Reverse the digits in a given number '''

num = int(input("Enter a number :  "))
absNum = abs(num)
rev = absNum % 10
absNum = absNum // 10
while (absNum > 0):
    r = absNum % 10 
    absNum = absNum // 10
    rev = rev*10 + r
# Now the result will be printed according to nature of number.
if(num >= 0):
    print(rev)
else:
    print(rev - 2*rev)

# in this code, we cannot predict how many number of times while loop gets executed. ence the range function cannot be used.

# We need to opt for 2nd feature of for loop which for each. we convert the given number into a string and proceed accordingly.

num = int(input("Enter a number :  "))
absStrnum = str(abs(num))
rev = '' 
# we create an empty string as we are doing al operations using strings.
for c in absStrnum:
    rev = c + rev # concatenation is done between the strings.
if(num >= 0):
    print(rev)
else:
    print('-' + rev)

''' Find whether the entered number is a Palindrome or not. '''

num = int(input("Enter a number :  "))
absNum = abs(num)
rev = absNum % 10
absNum = absNum // 10
while (absNum > 0):
    r = absNum % 10 
    absNum = absNum // 10
    rev = rev*10 + r
if(num <0):
    rev = rev-2*rev
    
if(num == rev):
    print("Palindrome")
else:
    print("Not a Palindrome")
    
# in this case as well we cannot trace the no. of iterations of the while loop. Hence while loop is used.
# We must apply the 2nd for loop approach which is 'for each' for this question to make it happen using for loop.

num = int(input("Enter a number :  "))
absStrNum = str(abs(num))
rev = ''

for c in absStrNum:
    rev = c + rev
if(num < 0):
    rev = '-' + rev
if(num == int(rev)):      # we must convert the string into an integer.
    print("Palindrome")
else:
    print("Not a Palindrome")<jupyter_output>Enter a number :  1221
Palindrome<jupyter_text>Nested For Loop<jupyter_code>s = 'VIBGYOR'
'''
print(s[0])
print(s[1])
print(s[2])
print(s[3])
print(s[4])
print(s[5])
print(s[6])'''

for i in range(7):
    print(s[i])
s = 'VIBGYOR'
t = 'VIBGYOR'

# s and t two brothers. They wear one of the coulors each day.
# What are all possible ways that s and t can wear ?

# example for a nested loop
count = 0

for i in range(7):
    for j in range(7):
        print(i,j,s[i],s[j])
        count = count + 1

print("The total ways in which the two brothers can wear 7 diff. colours:",count)
# i = 0, j = 0 print VV
# i = 0, j = 1 print VI
# i = 0, j = 2 print VB
#.....

# to make it interesting we can print i and j as well.<jupyter_output>0 0 V V
0 1 V I
0 2 V B
0 3 V G
0 4 V Y
0 5 V O
0 6 V R
1 0 I V
1 1 I I
1 2 I B
1 3 I G
1 4 I Y
1 5 I O
1 6 I R
2 0 B V
2 1 B I
2 2 B B
2 3 B G
2 4 B Y
2 5 B O
2 6 B R
3 0 G V
3 1 G I
3 2 G B
3 3 G G
3 4 G Y
3 5 G O
3 6 G R
4 0 Y V
4 1 Y I
4 2 Y B
4 3 Y G
4 4 Y Y
4 5 Y O
4 6 Y R
5 0 O V
5 1 O I
5 2 O B
5 3 O G
5 4 O Y
5 5 O O
5 6 O R
6 0 R V
6 1 R I
6 2 R B
6 3 R G
6 4 R Y
6 5 R O
6 6 R R
The total ways in which the two brothers can wear 7 diff. colours: 49<jupyter_text>Tutorial on Nested Loops<jupyter_code># we have studied two loops which are while and for.
# Nesting can be done in any manner like for in for, while in while, while in for , for in while.

''' Problem 1 : find all prime numbers less than entered number '''

num = int(input("Enter a number :"))
if (num>2):
    print(2, end = ' ')
    
for i in range(3, num):
    flag = False
    for j in range(2,i): # i represents the value of outer iteration.
        if (i % j == 0):
            flag = False
            break # only breaks the inner if loop.
        else:
            flag = True
    if (flag):
        print(i, end = ' ')<jupyter_output>Enter a number :10
2 3 5 7<jupyter_text>break , continue and pass keywords  break keyword<jupyter_code># consider a mail id to be <EMAIL>
email = input()
for c in email:
    if(c == '@'): # this loop doesn't get executed until c is @
        break
    print(c)

# the function of exit and break is identical, these simply stops execution of a loop.<jupyter_output><EMAIL>
a
b
c<jupyter_text>continue keyword<jupyter_code># We can get the username of email id in the first line and domain name in second line.
# the keyword continue is used to skip an iteration.
email = input()
for c in email:
    if(c == '@'):
        print('')
        continue
    print(c, end = '')<jupyter_output><EMAIL>
abc
xyz.in<jupyter_text>pass keyword<jupyter_code># the keyword pass is a just a placeholder and performs no operation. 
for x in range(11):
    if(x % 3 == 0):
        print(x)
    else:
        pass #this is where we use pass.
    
# there is a difference between comment and pass. We get an EOF error when there's no line written.
# If there's pass keyword, compiler understands the keyword and interprets the code accordingly.<jupyter_output>0
3
6
9
{'fraction_non_alphanumeric': 0.10749874182184198, 'fraction_numerical': 0.04267740312028183, 'mean_word_length': 3.180727961287608, 'pattern_counts': {'":': 0, '<': 90, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '287566', 'license': 'Apache-2.0', 'n_tokens_mistral': 7421, 'n_tokens_neox': 6778, 'n_words': 3185, 'path': 'Week 3 IIT MADRAS.ipynb', 'repo_name': 'SaiPrasanth212/IIT-MADRAS-PYTHON', 'size': '19879'}