Python
Container Types
list vs tuple vs dict vs set

List-tuple-dictionary-set differences, summarizing when to use them

Python has four built-in container types: List, Tuple, Dictionary, Set.

In this post, we'll compare the properties of each type and summarize when to use them.

1. Lists vs. Tuples

Lists and tuples are the most similar types. For starters, both types have an order, and you can use an index to get their elements. Also, you can have multiple types of elements in a single list or tuple. Because of this, you can use both types in many cases.

To clarify the uses of both types, it's important to note the differences. In this section, we'll discuss the differences between the two types to give you some guidance on when to use them.

1.1. Immutability

The most important difference between lists and tuples is immutability. Lists can be freely added and deleted, and elements in a list can be easily modified. Tuples, on the other hand, cannot be added, deleted, or modified once they are declared.

Let's think about when we need immutability in a real application and when we don't.

We have been tasked with implementing several features of a shopping cart using Python's container types. The basic features of a shopping cart that need to be addable and removable are the product list, the shopping cart, and the user list. These features should use lists.

Conversely, what features need to be immutable? You might think of metadata that doesn't change, such as a user's username, login date, or a merchant's business license number. This information is best stored in tuples so that the data can't be inadvertently changed.

Thinking about immutability in your application design will also help you communicate with other developers. This is because you can express in the code itself that a feature implemented as a list is immutable, while a feature implemented as a tuple should not be modified.

1.2. Type Diversity

As mentioned earlier, both lists and tuples can contain elements of multiple types together. However, if we think of them as an extension of the previous section, the story can be different.

We mentioned that lists are used for things like form lists, shopping cart lists, user lists, and so on. These lists poach the same kinds of items. A shopping cart list would contain only products, a user list would contain only users, and so on.

users = [user1, user2, user3].

On the other hand, if we think of a user's metadata as a tuple, the elements of the tuple would be of different types.

User1 = ('ID', 'Created At', 'Business Registration Number', ... )

And these tuples of data can be assembled into a list.

Users = [
    ('User1', 'ID', 'Created At', 'Business Registration Number', ... )
    ('User2', 'ID', 'Created At', 'Business Registration Number', ... )
    ('User3', 'ID', 'Created At', 'Business Registration Number', ... )
]

1.3. Summary

In summary, tuples can be used to hold various pieces of information about a single object, acting as a simple class. Lists can be used to manage multiple objects consisting of tuples as a list. These are the most common uses of lists and tuples.

We'll mention one more here. The list of products in a shopping cart should be accessible only to cart users, and the list of users should be accessible only to service administrators. That's a rule that's not going to change. So why not manage the lists that are accessible to different users as tuples like this?

admin_lists = ([User1, User2, ... ], ... )
customer_lists = ([article1, article2, ... ], ... )

As you can see, when you include a list in a tuple, the elements of that list are modifiable. This is because the immutability of the tuple applies to the reference to the list itself, not to the elements it contains.

2. Dictionaries

The main feature that distinguishes dictionaries from the other three types is the key-value pairs that make up a dictionary.

The keys of a dictionary act like the indices of a list or tuple. Whereas a list or tuple would use a numeric index to retrieve a particular element, a dictionary can use any type with guaranteed immutability as a key to retrieve a value.

These immutable keys can then be used as targets for the hash table on which the dictionary is based. This has the advantage that checking whether a key is contained in a dictionary, or retrieving a value by a key, can be done with O(1) time complexity on average. This is economical compared to traversing lists and tuples for up to O(n) to determine whether an element is included or not.

Because they're dictionaries that can use key values, they're actually easier to model than tuples. You can organize product information or user information as shown below. Especially for information that needs to be freely modifiable.

I'll cover this in a separate post, but immutable attribute information is easily managed with the NamedTuple type.

Item1 = {
    "name": "Product A",
    "price": 50.00,
    "description": "Description A",
    "stock": 10,
}
 
User1 = {
    "name": "John Doe",
    "email": "john@example.com",
    "address": "123 Street"
}

As you can see, Python dictionaries are a handy way to implement any object that needs properties and property values.

3. Sets

There are two main features that distinguish the set type from the other three types.

One is that it does not allow duplicates. Sets deduplicate themselves when you add a new value with the set.add() method, or when you convert another container type with the set() constructor. This makes deduplication easier than in other languages.

A popular deduplication pattern is to cast a type to a set and back again, as shown below.

numbers = [1, 2, 2, 3, 3, 3, 3, 4, 5].
 
unique_numbers = list(set(numbers))
print(unique_numbers)
 
# Output: [1, 2, 3, 4, 5]

The second property of sets is that they are effective for determining inclusion. In 2.Dictionaries, we saw that a hash table can be used to efficiently determine whether a key is included or not. The values in a set are also organized in a hash table. This allows us to quickly determine whether an item is included or not.

In addition, the set type has built-in methods to tell you about intersection, union, difference, and aggregation relationships. This also means that you don't have to write code for these functions.

For example, if you wanted to compare the containment relationships of two lists, you could do something like this

fruits_in_market = ['apple', 'banana', 'orange', 'pineapple'].
cart = ['banana', 'orange'].
 
set_fruits_in_market = set(fruits_in_market)
is_superset = set_fruits_in_market.issuperset(cart)
 
print(is_superset)
 
# Output: True

By converting just one of our lists to a set, we can do powerful things with simple code like the above.

Now let's consider the functionality of a shopping cart, which takes advantage of two great features of sets.

First, we can construct a list of categories from which we need to remove duplicates, as shown below, or we can use

product_categories = {"Electronics", "Books", "Clothing", "Home Decor", "Food"}

Comparing the wish list to the shopping cart set, we can also use the wish list to mark items in the shopping cart with a heart.

wish_list = ['iPhone 14 pro', 'PlayStaion 5', 'Bose QC 45'].
cart = ['PlayStaion 5', 'Nintendo Switch'].
 
heart_list = set(wish_list).intersection(cart)
 
print(heart_list)
 
# Output: {'PlayStaion 5'}

4. Conclusion

In this section, we've seen the features and uses of Python's built-in container types. I've summarized them to help you get a general idea of the four types, but always keep an open mind and think creatively about how to use them.

For more information on each type, see the corresponding sub-post.


© 2023 All rights reserved.