Showing posts with label Loops. Show all posts
Showing posts with label Loops. Show all posts

Friday, 28 September 2018

A simple database program

So we know how to get Python to run the most basic of SQLite commands - enough to maintain a table. As I discussed earlier, one of the big benefits of Python is that it can make SQLite commands more user friendly. Even if you don't use a GUI, Python can make command line interactions easier.
Building on the database I've been using in the previous posts, I've cooked up a Python program that makes using the historical figures database easier.

import sqlite3
conn = sqlite3.connect("C:\\sqlite\\db\\history1.db")
curs = conn.cursor()


def viewtable():
    curs.execute("SELECT * FROM historicalfigures ORDER BY Name;")
    fulldump = curs.fetchall()
    print("Name                  | Born  | Died  | Role                  | Nation")
    print("======================|=======|=======|=======================|=========")
    for line in fulldump:
        namestr = line[0]
        if len(namestr) >= 23:
            namestr = namestr[0:22]
        rolestr = line[3]
        if len(rolestr) >= 23:
            rolestr = rolestr[0:22]
        nationstr = line[4]
        if len(nationstr) >= 17:
            nationstr = nationstr[0:16]
        gapname = " " * (22 - len(namestr)) + "| "
        gapborn = "  | "
        gapdied = "  | "
        gaprole = " " * (22 - len(rolestr)) + "| "
        print(namestr + gapname + str(line[1]) + gapborn + str(line[2]) + gapdied + rolestr + gaprole + nationstr)
   

def searchtable():
    print("Searching table - please select which column ")
    print("Name ----(N)")
    print("Born ----(B)")
    print("Died ----(D)")
    print("Role ----(R)")
    print("Nation --(T)")
    fieldchoice = input("? ")
    fieldchoice = fieldchoice.lower()
    if fieldchoice == "n":
        term = input("What name? ")
        searchterm = "Name = '" + term + "'"
    elif fieldchoice == "b":
        compare = input("Do you want results before ( < ), in exact year ( = ) or after ( > )? ")
        term = input("Which Year? ")
        searchterm = "YearBirth "+ compare + " " + term
    elif fieldchoice == "d":
        field = "YearDeath"
        compare = input("Do you want results before ( < ), in exact year ( = ) or after ( > )? ")
        term = input("Which Year? ")   
        searchterm = "YearDeath "+ compare + " " + term
    elif fieldchoice == "r":
        term = input("What Role? ")
        searchterm = "Role LIKE '%"+ term +"%'"
    elif fieldchoice == "t":
        term = input("What Nation? ")
        searchterm = "Nation LIKE '%" + term + "%'"
    else:
        print("Sorry, option not recognised. ")
        return()
    print (searchterm)
    curs.execute("SELECT * FROM historicalfigures WHERE " + searchterm +";")
    searchdump = curs.fetchall()
    print("Name                   | Born  | Died  | Role                  | Nation")
    print("=======================|=======|=======|=======================|=========")
    for line in searchdump:
        gapname = " " * (23 - len(line[0])) + "|"
        gapborn = " " * 3 + "|"
        gapdied = " " * 3 + "|"
        gaprole = " " * (23 - len(line[3])) + "|"
        print(line[0] + gapname + str(line[1]) + gapborn + str(line[2]) + gapdied + line[3] + gaprole + line[4])
   
def enternew():
    print("Entering new record")
    newname = input("Please enter new name: ")
    newbirth = input("Please enter new year of birth: ")
    newdeath = input("Please enter new year of death: ")
    newrole = input("Please enter new role: ")
    newnation = input("Please enter new nation: ")
    keeper = input("Do you want to keep this new record (Y to keep, N to discard): ")
    keeper = keeper.lower()
    if keeper == "y":
        curs.execute("INSERT INTO historicalfigures (Name, YearBirth, YearDeath, Role, Nation) VALUES ('" + newname + "', "+ newbirth +", "+ newdeath +", '" + newrole + "', '" +newnation +"');")
        curs.execute("COMMIT;")
   

def deleterecord():
    curs.execute("SELECT Name FROM historicalfigures ORDER BY Name;")
    namedump = curs.fetchall()
    print("Current list of names is:")
    linecount = 0
    for line in namedump:
        print(linecount + " - " + line[0])
        linecount += 1
    whichline = input("Enter number of row to be deleted: ")
    whichline = int(whichline)
    delname = namedump[whichline][0]
    confirm = input("Please confirm (Y) or cancel (N) deleting record for " + delname +": ")
    confirm = confirm.lower()
    if confirm == 'y':
        curs.execute("DELETE FROM historicalfigures WHERE Name ='" + delname + "';")
        curs.execute("COMMIT;")
   

def updaterecord():
    curs.execute("SELECT Name FROM historicalfigures ORDER BY Name;")
    namedump = curs.fetchall()
    print("Current list of names is:")
    linecount = 0
    for line in namedump:
        print(str(linecount) + " - " + line[0])
        linecount += 1
    whichline = input("Enter number of row to be changed: ")
    whichline = int(whichline)
    updatename = namedump[whichline][0]
    curs.execute("SELECT * FROM historicalfigures WHERE Name = '"+ updatename+"';") 
    changedump = curs.fetchall()
    coltuple = ('Name', 'YearBirth', 'YearDeath', 'Role', 'Nation')
    colcount = 0
    for col in changedump[0]:
        print (str(colcount), coltuple[colcount], changedump[0][colcount])
        colcount += 1
    colchoice = input("Please enter number of column to change: ")
    colchoice = int(colchoice)
    newvalue = input("Please enter new value for this column: ")
    if colchoice == 0 or colchoice == 3 or colchoice == 4:
        newvalue = "'"+ newvalue +"'"
    print("About to change "+ coltuple[colchoice] +" to " + newvalue + " for "+ updatename)
    confirmchange = input("Confirm(Y) or discard (N): ")
    confirmchange = confirmchange.lower()
    if confirmchange == 'y':
        curs.execute("UPDATE historicalfigures SET "+ coltuple[colchoice] +" = "+ newvalue +" WHERE Name = '" + updatename + "';")
        curs.execute("COMMIT;")

print ("Historical Figures Table")
print ("========================")
cont = True
while cont == True:
    print ("Main menu - Please select an option")
    print ("View whole table ---V")
    print ("Search table -------S")
    print ("Enter new record ---E")
    print ("Delete record ------D")
    print ("Update record ------U")
    print ("Quit Program -------Q")
    optchoice = input("? ")
    optchoice = optchoice.lower()
    if optchoice == 'v':
        viewtable()
    elif optchoice == 's':
        searchtable()
    elif optchoice == 'e':
        enternew()
    elif optchoice == 'd':
        deleterecord()
    elif optchoice == 'u':
        updaterecord()
    elif optchoice == 'q':
        conn.close()
        cont = False
    else:
        print("Sorry, not recognised")



So this is big - bigger than any other program I've created for this blog. And what are the results like?

========= RESTART: C:\Users\pc\Documents\Programming\historical_2.py =========
Historical Figures Table
========================
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
? v
Name                  | Born  | Died  | Role                  | Nation
======================|=======|=======|=======================|=========
Cardinal Thomas Wolsey| 1473  | 1530  | Churchman & Politician | England
Christopher Columbus  | 1451  | 1509  | Explorer               | Spain & Italy
Elizabeth I           | 1533  | 1603  | Monarch                | England
Ferdinand Magellan    | 1480  | 1521  | Explorer               | Portugal
Francis Drake         | 1540  | 1596  | Explorer & Naval Comma | England
Henry VIII            | 1491  | 1547  | Monarch                | England
Leonardo da Vinci     | 1452  | 1519  | Artist                 | Italy
Niccolo Machiavelli   | 1469  | 1527  | Politician & Author    | Italy (Florence)
William Caxton        | 1422  | 1491  | Publisher              | England
William Shakespeare   | 1564  | 1616  | Author & Playwright    | England
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
?
========= RESTART: C:\Users\pc\Documents\Programming\historical_2.py =========
Historical Figures Table
========================
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
? v
Name                  | Born  | Died  | Role                  | Nation
======================|=======|=======|=======================|=========
Cardinal Thomas Wolsey| 1473  | 1530  | Churchman & Politician| England
Christopher Columbus  | 1451  | 1509  | Explorer              | Spain & Italy
Elizabeth I           | 1533  | 1603  | Monarch               | England
Ferdinand Magellan    | 1480  | 1521  | Explorer              | Portugal
Francis Drake         | 1540  | 1596  | Explorer & Naval Comma| England
Henry VIII            | 1491  | 1547  | Monarch               | England
Leonardo da Vinci     | 1452  | 1519  | Artist                | Italy
Niccolo Machiavelli   | 1469  | 1527  | Politician & Author   | Italy (Florence)
William Caxton        | 1422  | 1491  | Publisher             | England
William Shakespeare   | 1564  | 1616  | Author & Playwright   | England
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
? e
Entering new record
Please enter new name: Dante Alighieri
Please enter new year of birth: 1265
Please enter new year of death: 1321
Please enter new role: Author & Poet
Please enter new nation: Italy (Florence)
Do you want to keep this new record (Y to keep, N to discard): y
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
? y
Sorry, not recognised
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
? e
Entering new record
Please enter new name: Michelangelo di Lodovico Buonarotti Simoni
Please enter new year of birth: 1475
Please enter new year of death: 1564
Please enter new role: Artist
Please enter new nation: Italy (Florence & Rome)
Do you want to keep this new record (Y to keep, N to discard): y
Main menu - Please select an option
View whole table ---V
Search table -------S
Enter new record ---E
Delete record ------D
Update record ------U
Quit Program -------Q
? q
>>>


There are plenty of points I would like to make about this program:
  • It relies on functions to split the program into manageable chunks. Each choice (except Q to quit) in the main menu calls on a user-defined function defined before the main program.
  • I didn't need to reopen the connection to the database or recreate the cursor object when in the user-defined functions - they can automatically use the ones from the main program. 
  • The function viewtable()is about taking the list of tuples returned from SQLite by curs.fetchall() and presenting it neatly on the IDLE command line. One unforeseen problem is this blog has a narrower column width than the IDLE interface, so I've shrunk the font on the output to get the table to look neat. 
  • In viewtable() I have used slicing strings to make oversized text strings fit into columns, and repeating strings with * to fill with the right number of spaces. I'm hoping that all dates just have 4 digits. 
  • In searchtable() I have used user choices to assemble an SQL command. For searching both role and nation I have used the LIKE SQL comparator. This looks for records in a less exacting way than =  , and as here will find records where the searched-for string is part of that record's data in that field. So when searching the Role column, LIKE allows me to find author in a record whose Role field is author & playwright.  
  • All functions that involve changing the database have a confirming part, where if the user confirms they want to make the change, the COMMIT SQLite command is used. 
  • Both  deleterecord() and updaterecord() present a list of names (from the first column in the database) and allows the user to select the name by its index (its numerical position in the list). This name is then used as the identifier to make sure the right record in the database is updated or deleted as appropriate.  



Saturday, 22 September 2018

INSERT in SQLite and Using it in Python

Previously I looked at creating an SQLite database and  creating an empty table within it. The simplest way of getting data into a SQLite database table is to use the INSERT SQL command, and the simple version follows the format:
INSERT INTO tablename (column_list) VALUES (value_list);

Although not strictly necessary, I keep SQLite command and function names and keywords in UPPERCASE to remind me what they are. The other items in that command are variable. So if we go back to the table for historical figures we created, we might have an example of the INSERT function like:
INSERT INTO historicalfigures (Name, YearBirth, YearDeath, Role, Nation) VALUES ('Henry VIII', 1491, 1547, 'King', 'England');
That is just the SQL part. To get Python to do this, we need to do it via the cursor object (here given the variable name curs).
curs.execute("INSERT INTO historicalfigures (Name, YearBirth, YearDeath, Role, Nation) VALUES ('Henry VIII', 1491, 1547, 'King', 'England');")

That is longwinded, and not very clear. Do we need to do that every time we want to add a new row?
Yes and no.
Yes we need to get Python to tell SQL to do this, but no, we don't have to do this manually. This is where other parts of Python programming come in use in automating and easing this process.
Here is a script I have written to assist with this process:

import sqlite3
conn = sqlite3.connect("C:\\sqlite\\db\\history1.db")
curs = conn.cursor()

print("Historical Figure Data Entry")
nextentry = True
committed = False
while nextentry == True:
    nameentry = input("Name of person? ")
    birthentry = input("Year of Birth? ")
    if int(birthentry) < 2020:
        print("Valid Year")
    else:
        print("problem with year of birth")
    deathentry = input("Year of Death? ")
    if int(deathentry) < 2020:
        print("Valid Year")
    else:
        print("problem with year of death")
    roleentry = input("Role of person in history? ")
    nationentry = input("Main nation for person? ")
    print("Your data is: ", nameentry, birthentry, deathentry, roleentry, nationentry)
    keepit = input("Keep (Y) or Discard (N) ?")
    keepit = keepit.lower()
    if keepit == "y":
        committed = True
        curs.execute("INSERT INTO historicalfigures (Name, YearBirth, YearDeath, Role, Nation) VALUES ('"+nameentry+"', "+birthentry+", "+deathentry+", '"+roleentry+"', '"+nationentry+"');")
    nextchoice = input("Do you want to carry on with the next entry in the table? (Y/N)")
    nextchoice = nextchoice.lower()
    if nextchoice == 'y':
        nextentry = True
    else:
        nextentry = False
   
if committed == True:
    curs.execute("COMMIT;")
conn.close()

That's quite a bit, but there are aspects I want to point out to explain what is going on:
The bulk of the program is in a while loop so that it will repeat as long as the user wants to continue.
There are a lot of input statements to gather information from the user. Some of these change the flow of the program (by if or while structures) while others are the data fields that will be sent to the database.
This is shown in the really big line
        curs.execute("INSERT INTO historicalfigures (Name, YearBirth, YearDeath, Role, Nation) VALUES ('"+nameentry+"', "+birthentry+", "+deathentry+", '"+roleentry+"', '"+nationentry+"');")
that includes these variables in the executable statement.
The mix of single quotes and double quotes is to get round the problem that strings/text data in SQLite commands need to have quotes around them but Python will also be looking for the start and end of what it considers a string. As far as Python is concerned, a single quote inside a pair of double quotes is just a string character, not a delimiter (and this works vice versa).
At the end (second from last line) there is curs.execute("COMMIT;") - this is because changes to the database by INSERT and other commands are held in a temporary state by SQLite. If changes are made but then the COMMIT command is not used, the changes are discarded. This COMMIT command tells SQLite to keep the data changes.
However, if there are no changes, and then the COMMIT command is used, SQLite throws an error because there are no changes to be committed - hence the committed variable to tell the program if the COMMIT command should be sent to SQLite.

The end result? A more user-friendly way of entering data into our table:

=== RESTART: C:/Users/pc/Documents/Programming/historicalfigures_entry.py ===
Historical Figure Data Entry
Name of person? Leonardo da Vinci
Year of Birth? 1452
Valid Year
Year of Death? 1519
Valid Year
Role of person in history? Artist
Main nation for person? Italy
Your data is:  Leonardo da Vinci 1452 1519 Artist Italy
Keep (Y) or Discard (N) ?y
Do you want to carry on with the next entry in the table? (Y/N)n
>>>

Wednesday, 19 September 2018

Connecting to SQLite and Cursor Objects

SQLite, as mentioned in previous posts, is a software package for managing databases. It does so mainly through SQL, Standard Query Language. There are other database software packages that use SQL, namely MySQL (I didn't like it but you may have better luck), PostgreSQL and Oracle. SQLite has the nice feature that it integrates with programming languages such as Python, C++, Perl, Java and JavaScript.

So how do you use it? First you need to install it (my experience described here). Then you write a Python program that imports the sqlite3 module, connects to the database, and creates a virtual cursor. For example, if my SQLite is installed at C:\\sqlite and the database is at C:\\sqlite\db\base1.db then I create a connection by

import sqlite3 # only needed once at the start
conn = sqlite3.connect("C:\\SQLite\db\base1.db")

Remember when I looked at files, and I talked about creating a file object? This is basically what the conn variable represents. I think of it as a specialised file object, and the sqlite3 module allows us to interact in more varied ways with this file than just the usual read, write or append. 

Once you have made the connection with your chosen database you create what is called a cursor object. This is a virtual cursor - you don't see it flashing on your screen, but it enables you to pass SQL commands from Python to the SQLite program, and retrieve answers. 

So if we call our virtual cursor object curs (just a variable, but one I can recognise), we create it by
curs = conn.cursor()

Now we can tell Python to pass SQL commands to the SQLite program which will interact with the database. 
The bad news is SQL is a language in itself (that's what the L stands for). So the SQLite module lets you use a language within another language. 
The good news is SQL is not particularly difficult. 

One quick way of finding out the tables in a database is by querying the SQLite_master table. So the python command to run the SQL command is

curs.execute("SELECT * FROM sqlite_master WHERE type = 'table';")

Everything within the double quotes is being passed by the cursor object (curs) to the SQLite3 program. Also note the semi-colon at the end of each SQL command. This command on its own does not produce much on screen. If you are doing this on the IDLE command line rather than in a script, you might get a reply like
<sqlite3.Cursor object at 0x038DD360>
Not very informative. It's actually saying that a memory location has something from the cursor object. If execute() sends instructions from Python to SQL, then fetchall() and fetchone() bring back the reply.
I find it best to assign these replies to variables within Python. So
dump = curs.fetchall()
will retrieve whatever reply the curs object has received from SQL and pass it to Python, holding it in the variable dump. So what does dump hold?
>>> print(dump)
[('table', 'Location', 'Location', 2, 'CREATE TABLE Location(Scientific_name TEXT, Nation TEXT, Biome TEXT)')]
>>>

This might look like a mess, but a lot of queries will return in this format, and Python understands what this is. It is a list (denoted by the square brackets) that contains a tuple (denoted by the outer set of round brackets). The list is all the lines returned, with each line returned as a tuple - here it is just one line, so just one tuple within the list. Within the tuple, each element is the contents of the column (or field) for that row. In spreadsheet terms each element in the tuple would be a cell.

I admit this example is helped by the fact that I have already done some work on base1.db, so there is something to show for the queries.  It's like one of those "how to..." programmes on the TV where rather than going through the whole process, the presenter moves to a different workbench and announces "And here's one I did earlier" much to the frustration of the audience trying to follow.
So what tables are in this database? Just one, called Location (hence just one tuple in the response), and the final element in the tuple is actually the  SQL command used to create the table (here 'CREATE TABLE Location(Scientific_name TEXT, Nation TEXT, Biome TEXT)'. I won't go into a detailed explanation here.
So what if I then run the same two commands (execute() and fetchall()) for this table Location?
>>> curs.execute("SELECT * FROM Location;")
<sqlite3.Cursor object at 0x038DD360>
>>> dump2 = curs.fetchall()
>>> print(str(dump2))
[('Homo sapiens', 'United Kingdom', 'Urban'), ('Homo sapiens', 'United Kingdom', 'Rural'), ('Rattus norvegicus', 'United Kingdom', 'Urban'), ('Rattus norvegicus', 'United Kingdom', 'Rural'), ('Carcharodon carcharias', 'South Africa', 'Ocean'), ('Homo sapiens', 'South Africa', 'Urban'), ('Homo sapiens', 'South Africa', 'Ocean'), ('Carcharodon carcharias', 'Australia', 'Ocean'), ('Homo sapiens', 'Australia', 'Ocean')]


That's a mess (hence my choice of variable name).
But if I then tell Python to loop through the list (leaving the tuples as tuples) we get:
>>> for line in dump2:
 print(line)


('Homo sapiens', 'United Kingdom', 'Urban')
('Homo sapiens', 'United Kingdom', 'Rural')
('Rattus norvegicus', 'United Kingdom', 'Urban')
('Rattus norvegicus', 'United Kingdom', 'Rural')
('Carcharodon carcharias', 'South Africa', 'Ocean')
('Homo sapiens', 'South Africa', 'Urban')
('Homo sapiens', 'South Africa', 'Ocean')
('Carcharodon carcharias', 'Australia', 'Ocean')
('Homo sapiens', 'Australia', 'Ocean')
>>>

which is more clearly a table of results, with each tuple containing three elements (here Scientific Name, Nation and Biome respectively - biome is a biological term for what sort of habitat). This table actually was part of an early draft of the project I have been working on.

Finally, when finishing with SQLite, it is sensible to close any connections (again similar to closing a file object). This also closes the cursor object. So:
>>> conn.close()
>>> 

More later...

Thursday, 19 October 2017

A script to convert CSV to HTML tables

HTML can be a pain to write manually, especially when it comes to tables.
This script does the basics. It asks for and tries to open up the source file, then you give it the name of the new file the HTML table will be saved to.
It works on the very simple idea of splitting each row by its separator (which the user needs to specify, such as ; or ,) and then inserting the HTML 'separators' of <td> and </td>. It could be improved on - at the moment HTML/CSS formatting and style needs to be entered manually after conversion and there is no allowance for the first row being different. Nonetheless, I believe it could save me a lot of time and bother.
#!/usr/bin/python3
import sys

print ("HTML Table Maker!")
filechoice = input("Please enter name of file with data, including file extension: ")
try:
    FX= open(filechoice, 'r')
except:
    print("Invalid File Name!")
    exit()

print(FX.readline())
FX.seek(0) # Returns reading point back to top of file
sep = input("Please enter column separator: ")

newfile = input("New File name (inc. extension)? ")
FN = open(newfile, 'w')
FN.write('<table>\n')
for line in FX:
    linelist = line.split(sep)
    FN.write('\t<tr>')
    for col in linelist:
        FN.write('<td>'+col+'</td>')
    FN.write('</tr>\n')
FN.write('</table>\n')    
FX.close()
FN.close()

The line FX.seek(0) is a new thing - I may have mentioned before that when a Python program is writing to or reading from a file, it maintains a progress point, like a theoretical cursor. 
fileobject.seek(linenumber) resets this progress point to a particular line (in this case back to the start). 
And the output is as follows:
>>> ================================ RESTART ================================
>>> 
HTML Table Maker!
Please enter name of file with data, including file extension: groceries.csv
Butter (250g), 1.50, 2, 

Please enter column separator: ,
New File name (inc. extension)? groceries.html
>>> 
And now I can embed the contents of groceries.html into this blog page which is based on HTML:

Item NamePrice per ItemNumber of Items
Butter (250g)1.502
Chocolate Biscuits (300g)1.502
Flour (1kg)0.503
Milk (1 pint)0.705
Pork Sausages (500g)4.501
Rice (1kg)1.701
Strawberry Jam (400g)2.001

or even add a bit of formatting:

Item NamePrice per ItemNumber of Items
Butter (250g)1.502
Chocolate Biscuits (300g)1.502
Flour (1kg)0.503
Milk (1 pint)0.705
Pork Sausages (500g)4.501
Rice (1kg)1.701
Strawberry Jam (400g)2.001

Saturday, 16 September 2017

Combining For Loops and Maths

Here are some scripts I've done, partly to demonstrate what I have covered so far, partly just because I can.

Triangular Numbers


Have you ever arranged balls into an equilateral triangle? If you do fit them into a triangle, then one with equal sides is the easiest. This is seen particularly with snooker, pool and billiards. Clearly there is a fixed number of balls for each triangle, so a triangle with 4 balls per side has 10 balls, and a triangle with 5 balls per side has 15 balls. But what if you increased the balls per side? This program explores that.
#!/usr/bin/python3
count = 0
triangular = 0 # total number of balls in triangle
print ("Triangular Numbers")
size = input("Maximum side of triangle (integers only)? ")
size = int(size)
for x in range(size):
    count += 1
    triangular = triangular + count
    print("Count is " +str(count) + ", triangular is " + str(triangular))
 None of this is new to this blog, so I'll whiz through the main points.
  • Variables are initialised at the start
  • input() is used to get the maximum triangle size from the user
  • int() converts the user's input string to a number the program can use
  • A for loop repeats according to the size of the side of the triangle. 
  • count is increased by 1 every time the program goes through the loop 
  • Mathematically the formula is if the triangle has n balls per side, the number of balls in the triangle is [1 + 2+ .... + n] so this program keeps a running total until it reaches n. 
  • Although I briefly considered dropping the count variable and just using x, I realised that there would be problems with x starting at 0 and ending at size -1. Using the count variable gets around this. 
Due to the formatting of this blog, the final line is (for some viewers of this blog) unfortunately split into two and should read
 print("Count is " +str(count) + ", triangular is " + str(triangular))
 The difference between word wrap and end of line is not always obvious to humans, though it is important to Python. I hope the column width of this blog doesn't cause too many problems.
The output is:
 RESTART: C:/Users/John/Dropbox/Misc Programming/Python/python3/test19f_triangularnumbers.py
Triangular Numbers
Maximum side of triangle (integers only)? 12
Count is 1, triangular is 1
Count is 2, triangular is 3
Count is 3, triangular is 6
Count is 4, triangular is 10
Count is 5, triangular is 15
Count is 6, triangular is 21
Count is 7, triangular is 28
Count is 8, triangular is 36
Count is 9, triangular is 45
Count is 10, triangular is 55
Count is 11, triangular is 66
Count is 12, triangular is 78

>>>

 

Fibonacci Numbers

This is a sequence that is found in both nature and statistics and as it is a sequence of addition it has similarities to the triangular number sequence.
The sequence starts off with two numbers, 0 and 1. Add those together and put the result on the end. You now have 0, 1, 1. Repeat the process with the next two numbers at the end of the sequence, now 1 & 1, and append the result to the end of the sequence, which is now 0, 1, 1, 2. So now we take the last two numbers from the sequence....
You get the idea.
 Here's the code:
count = 0
a = 1
b = 0
maxcount = input("Maximum count? ")
maxcount = int(maxcount)
print("Count is " +str(count) + "  Fibonacci is " + str(a))
for count in range(maxcount):
    c = a + b
    b = a
    a = c   
    print("Count is " +str(count +1) + "  Fibonacci is " + str(c))
Nothing here is really new, though maybe the way I've juggled the variables, reassigning values between them is new.
And the output is:
 RESTART: C:\Users\John\Dropbox\Misc Programming\Python\python3\test19a_fibonacci.py
Maximum count? 7
Count is 0  Fibonacci is 1
Count is 1  Fibonacci is 1
Count is 2  Fibonacci is 2
Count is 3  Fibonacci is 3
Count is 4  Fibonacci is 5
Count is 5  Fibonacci is 8
Count is 6  Fibonacci is 13
Count is 7  Fibonacci is 21

>>>

Sunday, 10 September 2017

A Simple Loop

Back to coding: The next script in my collection is almost as simple as the first one.
#!/usr/bin/python3.5
for i in range(10):
    print ("Hello World")
This introduces a whole lot of new ideas that I shall briefly point out.
  • It is a for loop. Put simply, a for loop goes through a set of instructions a certain number of times. The i is a variable that here simply stands for each time the loop is repeated. Think of it as standing for instance or iteration. 
  • The in keyword tells Python this is the list or range of items that the for loop is working through
  • range is another keyword that tells Python a range of numbers is coming up or to create a range of numbers. In this case range(10) tells it to create the range of integers (whole numbers) up to 10. 
  • The colon and the indent are important parts of Python syntax - unlike a lot of programming languages such as Perl or Java where indenting the script is purely for human benefit, in Python the indents tell the interpreter where the instructions to be run for each cycle of the loop start and end. 
The output according to IDLE is:
>>>
 RESTART: C:\Users\John\Dropbox\Misc Programming\Python\python3\test02_for_loop.py
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World

>>>
 And hey presto, we have instructed the computer to print "Hello World" out 10 times!

There is something this script doesn't show - namely that the range of numbers created is not actually 1 to 10, but 0 to 9. This can catch a lot of new programmers out (including myself). By default, Python lists and ranges start at 0 rather than 1. This can be demonstrated by modifying the final line of the script so that it prints out i with each iteration of the loop:
#!/usr/bin/python3.5
for i in range(10):
    print (i, "Hello World")
gives the output in IDLE:
>>>
 RESTART: C:/Users/John/Dropbox/Misc Programming/Python/python3/test02a_for_loop.py
0 Hello World
1 Hello World
2 Hello World
3 Hello World
4 Hello World
5 Hello World
6 Hello World
7 Hello World
8 Hello World
9 Hello World

>>>