Lists and sequences using Runpython Console - Runpython-IntroProgramming/Course-Syllabus GitHub Wiki

For this tutorial you should use the runpython console.

Collections

One of Python's strengths is that it very good at handling lots of objects at once. One way Python lets you do this is by putting objects (like numbers or strings) into lists:

>>> someevens = [2,4,6,8,10,12,14,16,18,20]
>>> somenames = ['Tom', 'Dick', 'Harry']
>>> somelastnames = ['Wilson', 'Smith', 'Jones']

Once you have a list of things you can refer to individual items from the list, or sections of the list:

>>> someevens[4]   # Get the fifth element
10
>>> someevens[4:]  # Get a list starting with the fifth element
[10, 12, 14, 16, 18, 20]
>>> someevens[:4]  # Get a list ending with the element just before the fifth
[2, 4, 6, 8]
>>> someevens[:]  # Get a list the starts at the beginning, and ends at the end
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
>>> someevens[2:4]  # Get a list that starts at the third and ends with the element just before fifth.
[6, 8]
>>> someevens[4:2:-1]  # Get a list that starts with fifth and ends with one after the third (going in reverse).
[10, 8]

The act of copying sections from a list using the [] is called slicing. The basic idea is:

[ start index : end index : step or direction ]

Omitting the start index means "from the beginning". Omitting the end means "to the end". Omitting the step means "increment go in order, element by element, from the beginning"

The lists (or sub-lists) that are returned by these are actually new list objects that are copied from the original list object. One interesting consequence of this is that the best way to make a copy of a complete list is to use the slicing syntax to return the entire original string. Like this:

listcopy = listoriginal[:]

You can change parts of a list too. Remember somelastnames?:

>>> somelastnames
['Wilson', 'Smith', 'Jones']
>>> somelastnames[1] = 'Ramalamadingdong'  # Change the middle of the list!
>>> somelastnames
['Wilson', 'Ramalamadingdong', 'Jones']

You can even assign variables to other variables, but it does not make a new copy of the object. Both names will point to the same list. Try this:

>>> morelastnames = somelastnames   # morelastnames refers to the same object as somelastnames
>>> print(morelastnames)
['Wilson', 'Ramalamadingdong', 'Jones']
>>> print(somelastnames)
['Wilson', 'Ramalamadingdong', 'Jones']
>>> somelastnames[1] = 'Boring'
>>> print(somelastnames)
['Wilson', 'Boring', 'Jones']
>>> print(morelastnames)
['Wilson', 'Boring', 'Jones']   # morelastnames still is the same object as somelastnames

I made a change to the list object somelastnames, and it changed not only somelastnames, it also changed morelastnames! This is because both variables were pointing to the same object. So variables are not exactly like a post office box model for computer memory. Different names (variables) can quite easily refer to the same object in memory. Objects in memory can have multiple names, just the way people do.

Generating Lists and List Comprehensions

Now it's time to make some magic with lists! You can use one list to generate another list. Suppose I want to generate a list of odd numbers from my list of even numbers:

>>> print(someevens)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
>>> someodds = [x+1 for x in someevens]
>>> print(someodds)
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21]

List Comprehenensions

This snippet of code: [x+1 for x in someevens] is called a list comprehension and it is one of Python's most powerful features. Programmers who pick up Python after learning languages like PHP or C++ often never figure out how to use the list comprehension because there is nothing like it in older languages.

The list comprehension works something like this:

[ <a rule for generating a list element from an existing element, x> for x in <the name of an existing list> ].

The sum() Function

If you have a list of numbers, one easy way to get the sum of the numbers is to use the sum() function:

>>> nums = [1,2,3,4,5,6,7,8,9]
>>> total = sum(nums)
>>> total
45

The range() Function

If you need a quick way of generating a list of integers, use the built in range function:

>>> hundred = range(1,100)
>>> print(hundred)   # Python actually gave us an iterator
range(1, 100)
>>> print(list(hundred))   # To make an actual list from the iterator, use the list function with it
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

Notice that when I first tried to print the result of range(1,100), Python just regurgitated the command that I originally used. The range function actually produces an iterator, which is a special Python object for making lists. Python won't actually bother making the list until you want it, however. You can tell Python to make an actual list from an iterator by using the iterator inside the list function.

You can zip two lists together and make a list of tiny tuples (a tuple is a special kind of list that can't be modified):

>>> evenodd = zip(someevens, someodds)
>>> print(evenodd)   # evenodd is an iterator object
<zip object at 0x103983d08>
>>> print(list(evenodd))   # this turns evenodd into a list of even/odd number pairs
[(2, 3), (4, 5), (6, 7), (8, 9), (10, 11), (12, 13), (14, 15), (16, 17), (18, 19), (20, 21)]

Lambda Functions

If you have a quick mathematical operation that you'd like to repeat with lots of different numbers you could make your own function. For example, if I want a quick way to convert degrees Fahrenheit to degrees Celsius:

>>> celsius = lambda f: (f-32.0)/1.8
>>> print(celsius(32))
0.0
>>> print(celsius(70))
21.1111111111

The statement, lambda, generates a function object in computer memory. This function takes a single input argument or parameter, which f will point to. The behavior of the function is determined by the part following the colon: (f-32.0)/1.8. This will perform a little math on whatever argument is passed to the function and return the answer. Finally, this new function object will be assigned to the variable, celsius, so we can execute the function at any time by writing something like, celsius(100.0).

Putting it Together

Suppose I have a list of numbers that represent temperatures in Fahrenheit, and I would like to make a new list of the converted temperatures in Celsius. With my new celsius function and the list generating idea:

>>> f_temperatures = [32.0, 15.5, -55.3, 62, 36.3]
>>> c_temperatures = [celsius(x) for x in f_temperatures]
>>> print(c_temperatures)
[0.0, -9.1666666666666661, -48.5, 16.666666666666668, 2.3888888888888871]

You could also use a builtin Python function, map, to do a similar thing:

>>> c = map(celsius, f_temperatures)
>>> print(c)   # map makes an iterator object
<map object at 0x1039710b8>
>>> print(list(c))  # and the iterator can be used to make a list
[0.0, -9.166666666666666, -48.5, 16.666666666666668, 2.388888888888887]

Questions

  1. Write your own lambda function that converts inches to cm.

  2. Use your lambda function to convert the following list to cm:

inchlist = [20, 13, 1.0]


3. Create a lambda function called ```mysum``` that adds two arguments together.

   ```python
print(mysum(3, 5.5))
8.5
  1. Is it possible to write a lambda function that returns two values? You may have to research this!

  2. Write one line of Python code that computes the sum of all counting numbers between 1 and 1000, inclusive. The answer should be 500500.

  3. What do you think will be the output of the following code:

    print(list(zip([1, 2, 3], [3, 2, 1])))