# Chapter 15 - More on Data Types

## 15.1 - Tuples

A tuple is essentially an immutable list. Tuples, like strings, cannot be modified after creation. However, a tuple is different to a string in that while strings consist solely of characters, a tuple can contain objects of any type (like a list).

To create a tuple we use the comma operator:

``````>>> my_tuple = 2, 4, 8, 16
>>> my_tuple
(2, 4, 8, 16)``````

We typically encapsulate a tuple in parenthesis as it makes things easier to read.

``````>>> my_tuple = ("Hello", 6, 3.14)
>>> my_tuple
("Hello", 6, 3.14)``````

To create a tuple with a single value you must include a comma!

``````>>> t = (4,)
>>> type(t)
<class 'tuple'>
>>> v = (4)
>>> type(v)
<class 'int'>``````

We can concatenate tuples using the `+` operator and repeat tuples using the `*` operator:

``````>>> t = (2, 4, 6, 8)
>>> u = (1, 3, 5, 7)
>>> t + u
(2, 4, 6, 8, 1, 3, 5, 7)
>>> t * 2
(2, 4, 6, 8, 2, 4, 6, 8)``````

We can also slice and index in the same way we do with strings:

``````>>> t = (5, 4, 3, 2, 1)
>>> t[3]
2
>>> t[::-1]
(1, 2, 3, 4, 5)
>>> t[1:3]
(4, 3)``````

We can also iterate over tuples using loops. I'm going to use the `for` loop here but you can use `while` too:

``````>>> chars = ("a", "b", "c")
>>> for c in chars:
...     print(c)
...
a
b
c``````

We can use the `in` operator to check if a value exists in a tuple

``````>>> t = ("John", "Liam", "Tony")
>>> print("Tony" in t)
True``````

And lastly, as expected, we get an error if we try to change a tuples contents:

``````>>> t = (1, 2, 3)
>>> t[0] = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment``````

If you remember back to the chapter on dictionaries, the `d.item()` method returns a list of tuples.

``````>>> d = {"a": 10, "b": 11, "c": 12}
>>> for (k, v) in d.items():
...     print(k, v)
...
a 10
b 11
c 12``````

## 15.2 - Sets

A set is a collection of objects of arbitrary type. The set's objects are called its members. Set's are an unordered type (like dictionaries). They are also iterable. An important feature of sets is that they only contain one copy of a particular object i.e. duplicates are not allowed. Sets are mutable types.

Sets are generally used for membership testing and removing duplicates. They usually hold a collection of similar items.

To take full advantage of sets, you'll need to have a good understanding of set theory. I won't be covering set theory in this book so you can read up on it here: Introduction to Set Theory. You may however be familiar with basic set theory as you covered it in school. Set's are very important and are one of the data types that creep up in interviews.

In Python, a set is created using the `set()` function.

``x = set() # s is now an empty set``

We can also create a set using comma separated values enclosed in curly braces:

``x = {1, 2, 3, 4}``

Note that we cannot use `{}` to create an empty set as this would create an empty dictionary.

We use the `in` operator to check for membership:

``````>>> x = {2, 4, 6, 8}
>>> 6 in x
True``````

When we use the `in` operator on strings and lists, the runtime complexity is O(n). When we use this operator on sets it's on average O(1). This is the same with dictionaries. It is therefore very fast to access.

To add a new member to a set we use the `add()` method:

``````>>> x = {2, 4, 6}
>>> x
{8, 2, 4, 6}``````

Notice how the set doesn't have an order.

We can get the length of a set using the `len()` function:

``````>>> x = {2, 4, 6}
>>> len(x)
3``````

We can also create a set from other objects:

``````>>> s = set("abcdefghijk")
>>> s
{'d', 'e', 'i', 'h', 'k', 'g', 'j', 'f', 'a', 'b', 'c'}
>>> x = set([2, 4, 6, 8])
>>> x
{8, 2, 4, 6}``````

Remember: Duplicates are removed from sets!

``````>>> my_list = [2, 2, 6, 4, 5, 4, 4, 9]
>>> my_set = set(my_list)
>>> my_set
{9, 2, 4, 5, 6}``````

This is particularly useful when searching for unique elements in something.

We can get the intersection of two sets A and B using the `intersection()` method. This will return a set which contains the elements that are common to both A and B:

``````>>> A = {2, 3, 4, 5, 6, 7}
>>> B = {4, 5, 6, 10, 34, 22, 1}
>>> A.intersection(B)
{4, 5, 6}``````

We can get the union of two sets A and B using the `union()` method. The union of two sets is the set of elements in both A and B:

``````>>> A = {1, 3, 3, 7}
>>> B = {2, 3, 6, 8}
>>> A.union(B)
{1, 2, 3, 6, 7, 8}``````

We can get the set difference between two sets A and B using the `difference()` method. The A set difference B is the set of elements in A but not in B. Likewise, B set difference A is the set of elements in B but not in A:

``````>>> A = {1, 2, 3, 4, 5, 6}
>>> B = {4, 5, 6, 7, 8, 9}
>>> A.difference(B)
{1, 2, 3}
>>> B.difference(A)
{8, 9, 7}``````

We can also check if set B is a subset of A using the `issubset()` method. Set A is a subset of set B if every member of A is also a member of B:

``````>>> A = {2, 4, 6}
>>> B = {1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> A.issubset(B)
True
>>> B.issubset(A)
False``````

We can check if A is a superset of B using the `issuperset()` method. B is a superset of A if every member of A is also a member of B:

``````>>> A = {2, 4, 6}
>>> B = {1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> B.issuperset(A)
True
>>> A.issuperset(B)
False``````

## 15.3 - Lists & list comprehensions

We've seen how to create lists and you should be used to doing it at this point. However consider the following task:

Write a program that builds a list that contains all the even numbers from a second list.

The task of building one list by processing elements from another list is a very common task in computing. Until now we have had to use some kind of loop to iterate over all the elements in the second list and pick out the even numbers. Python has provided a short-cut for this called a list comprehension. You have seen me using a list comprehension in a previous chapter to build a list of 1,000 integers.

In this section we're going to look at how to create list comprehensions.

A list comprehension is a short-cut for building one list from another.

The syntax for a list comprehension is: `[expression for-clause condition]`.

For example to create a list that contains every number from 0 to 1,000 we could use the following list comprehension:

``lst = [x for x in range(0, 1000)]``

The above list comprehension reads: "Add x to the new list for each x in the list of elements from 0 to 1000".

To solve the task I mentioned at the beginning of this section we could use the following list comprehension:

``````>>> my_lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> evens = [x for x in my_lst if not x % 2]
>>> evens
[2, 4, 6, 8, 10, 12, 14]``````

In the above list comprehension, `x` is the expression, `for x in my_lst` is the for-clause and `if not x % 2` is the condition. It reads as follows: "Add x to the new list for each x in my_lst if x modulus 2 does not equal 0".

Remember, 0 is falsey, therefore, `if not x % 2` is True if x % 2 is equal to 0.

We can use a list comprehension to build up a list of squared values from another list using the following list comprehension:

``````>>> vals = [1, 2, 3, 4, 5, 6]
>>> squares = [x ** 2 for x in vals]
>>> squares
[1, 4, 9, 16, 25, 36]``````

Let's look at a list comprehension that will square the even numbers and leave any odd numbers the same:

``````>>> vals = [1, 2, 3, 4, 5, 6, 7, 8]
>>> evens_squared = [x ** 2 if not x % 2 else x for x in vals]
>>> evens_squared
[1, 4, 3, 16, 5, 36, 7, 64]``````

The above list comprehension reads as: "Add the square of x if x is even otherwise just x for each x in vals"

List comprehensions are so common to stumble across and you'll often see them being used if you research any problems online. They are generally a construct only found in Python. If you move on to Java for example in the future, you won't be able to use list comprehensions as they don't exist in Java.

Comprehensions don't just apply to lists. They can be used as short-cuts for building a new collection from another collections. We therefore have set and dictionary comprehensions:

``````>>> my_set = {x for x in range(10)}
>>> my_set
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> my_dict = {x:True for x in range(5)}
>>> my_dict
{0: True, 1: True, 2: True, 3: True, 4: True}``````

Practice with these! Use them when you can (which will probably be often). Making use of comprehensions is the Pythonic way of writing Python code.

## 15.4 - Exercises

You'll be using this for some of the exercises.

### Question 1

During a study, a number of software engineers were asked what their top 3 favourite programming languages were.

Write a program that determines the number of unique languages given as answers during the study. Below is the input file and each line is an answer given by a software engineer:

``````java python c++
python scala c
javascript python c
c c++ c#

Your program should be run as follows and give the following output:

``````\$ py unique.py input.txt
8``````

### Question 2

Write a list comprehension that creates a list containing all the odd numbers between 0 and 10,000.

### Question 3

Using the dictionary you downloaded earlier, write a program that builds a list containing all the words that are longer than or equal to 18 characters. You should use a list comprehension to do this!

Your program should be run as follows:

``\$ py long_words.py < dictionary.txt``

Note: This may take some time to run as the input file is large!

### Question 3

Using the dictionary you downloaded earlier, write a program that builds a list containing all the words that contain every vowel (a, e, i, o and u). For example, the word "equation" should be in the list. You should make good use of a list comprehension to do this!

Your program should be run as follows:

``\$ py vowels.py < dictionary.py``

### Question 4

Using the dictionary you downloaded earlier, write a program that builds a list containing all the words that contain exactly 4 a's and end in 'ian'. For example, the word "alabastrian" should be in the list. You should make good use of a list comprehension to do this!

Your program should be run as follows:

``\$ py two_conditions.py < dictionary.txt``

### Question 5

Using the dictionary you downloaded earlier, write a program that builds a list containing all the words in the dictionary whose reverse also occurs. For example, the words "lager" and "regal" should be in the list. You should make good use of comprehensions to do this!

Your program should be run as follows:

``\$ py reverse.py < dictionary.txt``

Tip: You may want to think about your solution for this. Your program may take a very long time to run if you don't implement a more efficient solution!

#### Help support the author by donating or purchasing a copy of the book (not available yet)

Previous Chapter - Next Chapter