mutating lists (slides)

CSc 110 - mutating lists

Lists are mutable

  • changes to a list in a function will remain after the function finishes running
  • changes to individual list elements do not change the list itself

Changing a list in a loop

Changes to individual list elements do not change the list itself

numbers = [1, 2, 1, 4, 5]
for n in numbers:
  n += 1
numbers
[1, 2, 1, 4, 5]

Use a for i in range loop instead:

numbers = [1, 2, 1, 4, 5]
for i in range(len(numbers)):
  numbers[i] += 1
numbers
[2, 3, 2, 5, 6]

Write a function

It takes a 2D list of integers as argument with at least one inner list. It mutates the list, replace each inner list with a tuple. The tuple is the total and mean of that inner list.

test_list = [[2, 4, 6, 8], [], [2, 3, 4]]
total_mean(test_list)
assert test_list == [(20, 5.0), (None, None), (9, 3.0)]
assert total_mean([[2, 4, 6, 8], [], [2, 3, 4]]) == [(20, 5.0), (None, None), (9, 3.0)]

Write a function – solution

line 2: can we use for sublist in lists?

line 7: can we use for n in lists[i]?

def total_mean(lists):
    for i in range(len(lists)): # 
        total = None
        mean = None
        if len(lists[i]) > 0: 
            total = 0
            for j in range(len(lists[i])): # 
                total += lists[i][j]
            mean = total/len(lists[i])
        lists[i] = total, mean 
    return lists

Write a function – solution

def total_mean(lists):
    for i in range(len(lists)): #must use for i in range(len(lists))
        total = None
        mean = None
        if len(lists[i]) > 0: 
            total = 0
            for j in range(len(lists[i])): #can also use for n in lists[i]
                total += lists[i][j]
            mean = total/len(lists[i])
        lists[i] = total, mean #need to use i to mutate lists
    return lists
    
def main():
  test_list = [[2, 4, 6, 8], [], [2, 3, 4]]
  total_mean(test_list)
  assert test_list == [(20, 5.0), (None, None), (9, 3.0)]
  assert total_mean([[2, 4, 6, 8], [], [2, 3, 4]]) == [(20, 5.0), (None, None), (9, 3.0)]
  
main()

Removing list elements in a loop

for i in range when removing list items throws an ERROR.

numbers = [1, 2, 1, 4, 5]
for i in range(len(numbers)):
  numbers.pop(i)
numbers

ERROR

Removing list elements in a loop

Visualize the execution in Python Tutor.

  • Option 1: while loop without adjusting i
numbers = [1, 2, 1, 4, 5]
i = 0
while i < len(numbers):
  numbers.pop(i)
numbers
[]
  • Option 2: for loop but go backwards
numbers = [1, 2, 1, 4, 5]
for i in range(len(numbers)-1, -1, -1):
  numbers.pop(i)
numbers
[]

Write a function

  1. Its name is remove_names
  2. It takes one argument: a list of strings
  3. It mutates and returns the argument list removing all strings that end in vowel

Name as delete_from_list.py, submit to Gradescope.

names = ["Beatrice", "ASA", "Philip", "Anna", "Peter"]
remove_names(names)
assert names == ["Philip", "Peter"]

Write a function – solution 1

def remove_names(string_list):
  i = 0
  while i < len(string_list):
    if string_list[i][-1].lower() in "aeiou":
      string_list.pop(i)
    else:
      i += 1
  return string_list
      
def main():
  names = ["Beatrice", "ASA", "Philip", "Anna", "Peter"]
  remove_names(names)
  assert names == ["Philip", "Peter"]

main()

Write a function – solution 2

def remove_names(string_list):
  for i in range(len(string_list)-1, -1, -1):
    if string_list[i][-1].lower() in "aeiou":
      string_list.pop(i)
  return string_list
      
def main():
  names = ["Beatrice", "ASA", "Philip", "Anna", "Peter"]
  remove_names(names)
  assert names == ["Philip", "Peter"]

main()

Removing elements from inner lists in 2D lists

lists_of_numbers = [ [2, 3, 1, 2], [4, 5, 2, 1] ]
for inner_list in lists_of_numbers:
  for i in range(len(inner_list)-1, -1, -1):
    inner_list.pop(i)
    
print(lists_of_numbers)
[[], []]

Write a function

  1. Its name is remove_odds
  2. It takes a list of lists of integers as argument
  3. It mutates the inner list, removing odd numbers
lists_of_numbers = [ [2, 3, 1, 2], [4, 5, 2, 1] ]
remove_odds(lists_of_numbers)
assert lists_of_numbers == [ [2, 2], [4, 2] ]

Write a function – solution

def remove_odds(lists):
  for i in range(len(lists)):
    for j in range(len(lists[i])-1, -1, -1):
      if lists[i][j] % 2 != 0:
        lists[i].pop(j)
  return lists

def main():
  test_list = [ [2, 3, 1, 2], [4, 5, 2, 1] ]
  remove_odds(test_list)
  assert test_list == [ [2, 2], [4, 2] ]
  print(test_list) # [ [2, 2], [4, 2] ]
  
main()
[[2, 2], [4, 2]]

Write a function – questions

line 2: can we use for innerlist in lists?

line 3: can we use for X in list?

def remove_odds(lists):
  for i in range(len(lists)): #
    for j in range(len(lists[i])-1, -1, -1): #
      if lists[i][j] % 2 != 0:
        lists[i].pop(j)
  return lists

Write a function – answers

def remove_odds(lists):
  for inner_list in lists: # yes we can
    for i in range(len(inner_list)-1, -1, -1): # no 
      if inner_list[i] % 2 != 0:
        inner_list.pop(i)
  return lists

def main():
  test_list = [ [2, 3, 1, 2], [4, 5, 2, 1] ]
  remove_odds(test_list)
  assert test_list == [ [2, 2], [4, 2] ]
  print(test_list) # [ [2, 2], [4, 2] ]
  
main()
[[2, 2], [4, 2]]

Determine the ouput

data.txt

harsh sitting spins
daybed trees fox a b c

code.py

def write_result(input_filename, output_filename):
  data = open(input_filename, 'r')
  result = open(output_filename, 'w')
  for line in data:
    words = line.strip().split(' ')
    for w in words:
      if w[0] == w[-1]:
        result.write(w + '\n')
  data.close()
  result.close()
  
if __name__ == '__main__':
  write_result('data.txt', 'result.txt')