More list operations

Lists have a set of methods for adding, removing and rearranging. Most change the list in place and return nothing.

Adding and removing

items = ["apple", "bread", "milk"]
items.insert(1, "eggs")
print(items)

last = items.pop()
print(last)
print(items)

insert(position, value) puts a value at a position, shifting the rest along. pop() removes and returns the last item; pop(0) removes the first.

remove(value) deletes the first matching value only. If the value appears twice, the second one stays. Removing a value that is not there is an error.

items = ["apple", "bread", "apple", "milk"]
items.remove("apple")
print(items)

Finding and counting

index also stops at the first match. count looks at the whole list.

items = ["apple", "bread", "apple", "milk"]
print(items.index("apple"))
print(items.index("apple", 1))
print(items.count("apple"))

items.index("apple", 1) starts searching from position 1, which is how you find the second occurrence. Check with in first if the value might be absent, because index raises an error when it is.

Sorting and reversing

prices = [40, 2.5, 25]
prices.sort()
print(prices)

prices.reverse()
print(prices)

sort and reverse change the list in place and return None, like append. This is the same trap as before:

prices = [40, 2.5, 25]
prices = prices.sort()
print(prices)

If you want a sorted copy and the original untouched, use the sorted function, which returns a new list:

prices = [40, 2.5, 25]
cheapest_first = sorted(prices)
print(cheapest_first)
print(prices)

Strings sort alphabetically, but every capital letter comes before every lowercase one, so "Milk" sorts ahead of "apple". reverse=True sorts descending. That is an option passed by name, which is how Python handles settings a function does not always need; prices.sort(reverse=True) works the same way.

items = ["bread", "Milk", "apple"]
print(sorted(items))
print(sorted(items, reverse=True))

A list that mixes numbers and strings cannot be sorted at all. Python has no rule for whether "apple" is less than 40, so it refuses:

mixed = ["apple", 40, "bread"]
mixed.sort()

Two names, one list

This surprises everyone once. Assigning a list to a second name does not copy it. Both names refer to the same list, so a change through one shows through the other.

original = ["apple", "bread"]
alias = original
alias.append("milk")
print(original)

To get an independent copy, slice the whole thing with [:], or pass the list to list(), which builds a new list from anything you can loop over:

original = ["apple", "bread"]
copy = original[:]
copy.append("milk")
print(original)
print(copy)

another = list(original)
another.append("eggs")
print(original)
print(another)

Strings and numbers never have this problem because they cannot be changed in place. Lists can, so it matters which list a name points at.

Try it

Remove a sold-out item

Write remove_item(items, item) that removes item from the list if it is there, and leaves the list alone if it is not. If item appears more than once, remove only the first one. Change the list itself and return it.

remove_item(["apple", "bread", "milk"], "bread")  ->  ["apple", "milk"]
remove_item(["apple", "milk"], "eggs")            ->  ["apple", "milk"]
remove_item(["a", "b", "a"], "a")                 ->  ["b", "a"]
def remove_item(items, item):
    ...

Cheapest first

Write cheapest_first(prices) that returns a new list with the prices in ascending order, leaving the original list unchanged.

cheapest_first([40, 2.5, 25])  ->  [2.5, 25, 40]
def cheapest_first(prices):
    ...

Copy, then extend

Write with_extra(items, extra) that returns a new list containing everything in items followed by extra, without changing items.

with_extra(["apple", "bread"], "milk")  ->  ["apple", "bread", "milk"]
def with_extra(items, extra):
    ...

Next: While loops.