Lists#

Creating, Initializing and Populating Lists#

Lists are created using square brackets [] and populated using calls to <variable_name>.append(value)

sequence = [0, 1, 2, -6]
sequence.append(5.42)
sequence.append(1)
sequence.append("south carolina")

print(sequence)
[0, 1, 2, -6, 5.42, 1, 'south carolina']

Lists can also initialized with square brackets [] and , separated values:

sequence = [0, 1, 0]

Question 1. Create a list and populate it using 100 successive calls to randint(0, 1) in a while loop.

from random import randint

sequence = []
i = 1
while i <= 100:
    sequence.append(randint(0, 1))
    i = i + 1
    
print(sequence)
[0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1]

Length of a list#

  • You can access the length of a list using len

sequence = [1, 2,34, "Fahad", "Furman"]
len(sequence)
5

Accessing List Items#

  • Items in a list are indexed from 0 to len(list) - 1

    • The indexing is left to right in increasing order

    • The first item in the list is the first one appended and appears at index 0

      • Subsequent items can be accessed using indicies 1, 2, 3 and so on…

  • You can access items in a list by referring to the index number within square brackets

new_list = ["furman", "at", "south", "carolina"]

new_list[len(new_list)-1]
'carolina'
  • If you try to access an item in the list using an index > len(list)-1

    • IndexError: list index out of range

sequence = [0, 1, 0]

sequence[4]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Input In [6], in <cell line: 3>()
      1 sequence = [0, 1, 0]
----> 3 sequence[4]

IndexError: list index out of range

Remove List Item#

  • An item in the list can be removed using .pop()

    • Removes the item at the highest index value (right most item)

      • Removes from list and returns it

help(sequence.pop)
Help on built-in function pop:

pop(index=-1, /) method of builtins.list instance
    Remove and return item at index (default last).
    
    Raises IndexError if list is empty or index is out of range.
sequence = ["a", "b", "c"]

removed_item = sequence.pop()

print(sequence)

print(removed_item)
['a', 'b']
c
  • An alternative method to remove an item in the list is to use .remove(value)

  • .remove(value) takes as input value

    • If value is present in the list, it is removed

    • If value is not in the list, ValueError is raised

    • If multiple occurences of value are present, first occurence is removed

help(sequence.remove)
Help on built-in function remove:

remove(value, /) method of builtins.list instance
    Remove first occurrence of value.
    
    Raises ValueError if the value is not present.
sequence = [1, 2, 3, 4, 1]

x = sequence.remove(1)

print(sequence)

y = sequence.remove(1)

print(x, y)
[2, 3, 4, 1]
None None

Change Item Value#

To change the value at a particular index, use square brackets with index number sequence[index] and assignment operator =

sequence = ['south', 'carolina']
sequence[0] = "north"
print(sequence)
sequence[1] = "dakota"
print(sequence)
sequence.append("state")
print(sequence)
['north', 'carolina']
['north', 'dakota']
['north', 'dakota', 'state']
  • Note again that you can only change existing values in the list

    • That were either appending using append or

    • Were part of the list during initialization

  • You cannot add a new item to the list using sequence[index] = new_item

  • The index must be within range 0 to len(list)-1

sequence = ['a', 'b']

sequence[  = 'c'
rainbow = ["Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"]

Slicing#

  • Slicing allows accessing a sublist within a list

    • Think of it as grabbing a slice of pizza/pie/bread

  • You can slice a list using a range of indices that specify where to start and where to end the slice

    • Syntax: list_variable[start:end] where start and end are indices.

    • Indices are always integers!

    • Starting index is included. Ending index is excluded.

  • When slicing a list, the return value will be the new list with the relevant items.

rainbow = ["Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"]
print(rainbow[0: 2])
['Red', 'Orange']
  • When start index is not explicitly stated in slicing, the default value is 0

print(rainbow[:4])

print(rainbow)
['Red', 'Orange', 'Yellow', 'Green']
['Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet']
  • When end index is not explicitly stated in slicing, the default value is len(list)

print(rainbow[3:])

print(rainbow[3:len(rainbow)]==rainbow[3:])
['Green', 'Blue', 'Indigo', 'Violet']
True
  • start index has default value 0

  • end index has default value len(list)

print(rainbow[:])
print(rainbow[:] == rainbow[0:len(rainbow)])
['Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet']
True
  • When slicing, any indices >= len(list) will NOT result in IndexError

rainbow[1:9]
['Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet']

Negative indices#

  • Negative indices allow accessing items in the opposite direction

  • Largest negative index is -1 which refers to the last item, -2 refers to the second last item and so on..

rainbow[-8:]
['Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet']
rainbow[-3] == rainbow[4]

rainbow[0] == rainbow[-1*len(rainbow)]
True
  • Slicing with negative indices works in the same direction as when slicing with positive indices

rainbow[-7: 4]
['Red', 'Orange', 'Yellow', 'Green']

Matrices (Nested Lists)#

colors_matrix = [ ["Red", "Orange", "Maroon"],\
                 ["Blue", "Indigo", "Violet"],\
                 ["Green", "Lime", "Olive"] ]

first_row = colors_matrix[0]
first_item = first_row[0]

first_item==colors_matrix[0][0]#, colors_matrix[1][0], colors_matrix[2][0]
True
colors_matrix = [ ["Red", "Orange", "Maroon"], ["Blue", "Indigo", "Violet"], ["Green", "Lime", "Olive"]]
colors_matrix[0]
['Red', 'Orange', 'Maroon']
colors_matrix = [ ["Red", "Orange", "Maroon"], None,\
                 ["Blue", "Indigo", "Violet"], ["Green", "Lime", "Olive"], \
                True, 8.0, 99]
type(colors_matrix[1])
NoneType

Arguments (Inputs) of type int, float, bool and str are passed by value#

  • Arguments (Inputs) to a function, of type int, float, bool and str, are passed by value

  • This means the input/arguments variables inside of a function are copies of variables from the caller.

  • Thus changing value of variables of these types inside a function does not change their values on the caller’s end.

def myfunc(x):

    print("Line 3 - Inside function and before updating, x =", x)
    
    x = x + 1
    
    print("Line 7 - Inside function and after updating, x =", x)


x = 1

print("Line 12 - Before function call x =", x)

myfunc(x)

print("Line 16 - After function call x =", x)
Line 12 - Before function call x = 1
Line 3 - Inside function and before updating, x = 1
Line 7 - Inside function and after updating, x = 2
Line 16 - After function call x = 1

Lists passed to Functions by Reference#

  • Variables of type list passed to functions are NOT passed by value but by Reference

  • This means the input/arguments variables inside of a function are NOT copies of variables from the caller

  • Changing value of list variables inside a function also changes their values on the caller’s end.

"""Passed by value: 
Integers, Booleans, Floats, 
"""
def func(val):
    val = 10
    
val = 2
func(val)
print(val)
2
"""Passed by reference"""
def func(list_input):
    list_input.append(10)
    
my_list = [1, 2, 3]
func(my_list)
print(my_list)
[1, 2, 3, 10]

Concatenating lists using +#

  • Multiple lists can be concatenated using the + operator in Python

  • The list1 + list2 performs the following operations in this order:

  1. Creates a new empty list for output

    • Operands lists remain unchanged

  2. Appends all items of list1 in the newly created list

  3. Appends all items of list2 in the newly created list

[1, 3] + [2, 4]
[1, 3, 2, 4]
([1, 2, 3] + [4, 5, 6]) + [7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Multiplying lists using *#

  • When a list is multiplied with a integer, say x, the list is concantenated to itself x times.

[1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
  • Multiplication of lists with negative numbers results in empty lists

  • Multiplication with floating point numbers not allowed

Operators not allowed with lists#

  • Python operations not allowed with lists (neither between two or more lists nor between list and numeric data types):

    • Subtraction -

    • Division (/)

    • Modulus (%)

    • Floor Division (//)

    • Exponential (**)

Recall [] == False#

bool(None), bool(0), bool([]), bool(""), bool(" "), bool("a")
(False, False, False, False, True, True)
if []:
    print('a')
else:
    print('b')
b

Implement csc105_min which takes as input a list x and returns the minimum value within x.

Using built-in functions not allowed

def csc105_min(x):
    
    return min_value

assert csc105_min([9, 8, 7, 0, 10]) == 0,    "Test case 1 failed"
assert csc105_min([])               == None, "Test case 2 failed"
assert csc105_min([1])              == 1,    "Test case 3 failed"
assert csc105_min([-99, 0, 99])     == -99,  "Test case 4 failed"
assert csc105_min([0, None, 99])    == 0,  "Test case 4 failed"