List vs Set in Python: Differences and When to Use Each

List vs set in Python comes down to this: a list keeps items in order and allows duplicates, while a set stores only unique items, has no positions, and checks membership much faster. Pick a list for sequences, a set for uniqueness and lookups:

cities = ["Austin", "Denver", "Austin"]   # ordered, duplicates kept
unique = {"Austin", "Denver"}             # unordered, unique

I timed and printed every comparison below on Python 3.12.5, using US cities and fake customer emails.

We’ll compare order and duplicates, what can go inside each, lookup speed, set math for comparing groups, removing duplicates while keeping order, and memory use.

List vs set: the key differences

ListSet
Syntax[1, 2, 3]{1, 2, 3} (empty: set())
OrderKeptNot guaranteed
DuplicatesAllowedRemoved automatically
Indexing x[0]YesNo
x in ... speedSlower as it grows (O(n))Fast on average (O(1))
Items must be hashableNoYes
Set math (union etc.)NoYes

Order, duplicates and indexing

Turn the same data into a list and a set and you’ll see the differences right away. The set drops repeats and has no first item, so indexing fails:

visits = ["Austin", "Denver", "Austin", "Boston", "Denver", "Austin"]

as_list = list(visits)
as_set = set(visits)

print("list:", as_list, len(as_list))     # keeps order and duplicates
print("set: ", as_set, len(as_set))       # unique items, no guaranteed order

print(as_list[0])                         # lists have positions
try:
    as_set[0]
except TypeError as err:
    print("TypeError:", err)

Output:

list: ['Austin', 'Denver', 'Austin', 'Boston', 'Denver', 'Austin'] 6
set:  {'Denver', 'Boston', 'Austin'} 3
Austin
TypeError: 'set' object is not subscriptable
Command Prompt output of a Python list keeping duplicate US city visits and a set keeping unique cities, with a TypeError for set indexing
Six visits in the list, three cities in the set. Sets aren’t subscriptable.

The set’s printed order can differ from run to run for strings, so never rely on it. For more on sets themselves, see set vs tuple in Python.

What can go in a list vs a set?

You can put anything in a list. A set only holds hashable items, which rules out lists and dicts. Convert inner lists to tuples first:

coords = [[30.27, -97.74], [39.74, -104.99]]

try:
    unique = set(coords)                  # lists can't go inside a set
except TypeError as err:
    print("TypeError:", err)

unique = set(map(tuple, coords))          # tuples can
print(unique)

lookup = {("Austin", "TX"): 979_882}      # tuples also work as dict keys
print(lookup[("Austin", "TX")])

Output:

TypeError: unhashable type: 'list'
{(30.27, -97.74), (39.74, -104.99)}
979882

Which is faster, a list or a set?

When you check whether something is present, I’d pick a set every time; it wins by a mile. A list scans items one at a time, while a set uses a hash table to jump to the answer:

import timeit

emails = [f"user{i}@example.com" for i in range(200_000)]
email_list = emails
email_set = set(emails)
target = "user199999@example.com"           # worst case for the list: the last item

t_list = timeit.timeit(lambda: target in email_list, number=200)
t_set = timeit.timeit(lambda: target in email_set, number=200)
print(f"in list: {t_list * 1000:8.2f} ms for 200 lookups")
print(f"in set:  {t_set * 1000:8.3f} ms for 200 lookups")

Output:

in list:   388.67 ms for 200 lookups
in set:     0.012 ms for 200 lookups
Command Prompt output timing membership tests on a list versus a set of 200,000 email addresses
Same 200 lookups: a few hundred milliseconds for the list, a tiny fraction of a millisecond for the set.

Lists are still fast for looping and for small collections. The rule of thumb: if you test in repeatedly on big data, convert to a set once. More in what in means in Python.

Comparing groups with set operations

Sets do the math you’d find awkward with lists: who’s on both lists, either list, or only one. These read almost like plain English:

newsletter = {"ann@example.com", "bo@example.com", "cy@example.com", "di@example.com"}
customers = {"bo@example.com", "di@example.com", "ed@example.com"}

print("both:              ", sorted(newsletter & customers))    # intersection
print("either:            ", sorted(newsletter | customers))    # union
print("subscribers only:  ", sorted(newsletter - customers))    # difference
print("in exactly one:    ", sorted(newsletter ^ customers))    # symmetric difference
print("customers all subscribed?", customers <= newsletter)

Output:

both:               ['bo@example.com', 'di@example.com']
either:             ['ann@example.com', 'bo@example.com', 'cy@example.com', 'di@example.com', 'ed@example.com']
subscribers only:   ['ann@example.com', 'cy@example.com']
in exactly one:     ['ann@example.com', 'cy@example.com', 'ed@example.com']
customers all subscribed? False
Command Prompt output of Python set intersection, union, difference and symmetric difference on newsletter and customer email sets
&, |, - and ^ answer marketing questions in one line each.

Removing duplicates from a list (and keeping order)

set(items) removes duplicates but scrambles the order. dict.fromkeys() removes them and keeps the first-seen order, because dictionaries preserve insertion order:

orders = ["A102", "A101", "A102", "A105", "A101", "A103"]

print(list(set(orders)))                  # unique, but order is lost
print(list(dict.fromkeys(orders)))        # unique AND in first-seen order
print(sorted(set(orders)))                # unique and sorted

Output:

['A101', 'A105', 'A103', 'A102']
['A102', 'A101', 'A105', 'A103']
['A101', 'A102', 'A103', 'A105']
Command Prompt output of removing duplicate order IDs with set, dict.fromkeys to keep order, and sorted set
Use dict.fromkeys() when order matters and sorted(set()) when you want them sorted.

There’s a full guide on merging lists without duplicates too.

Memory: sets cost more

Your set’s hash table needs extra room to stay fast, so it uses noticeably more memory than a list of the same numbers:

import sys

n = 100_000
data = list(range(n))
print(f"list of {n:,}: {sys.getsizeof(data):>9,} bytes")
print(f"set of  {n:,}: {sys.getsizeof(set(data)):>9,} bytes")

Output:

list of 100,000:   800,056 bytes
set of  100,000: 4,194,520 bytes

I think that trade-off is usually worth it for lookups. If you only ever loop over the data, a list is leaner.

When to use a list vs a set

Use a list whenUse a set when
Order mattersYou only care about unique values
You need duplicatesYou test membership often
You access items by positionYou compare groups (union, intersection)
You sort or slice the dataYou want to drop duplicates fast

More on Python collections:

Frequently asked questions

What’s the difference between a list and a set in Python?

A list is ordered and allows duplicates. A set is unordered, holds only unique hashable items, and checks membership much faster.

Is a set faster than a list in Python?

For in checks, yes, by a wide margin on large data. For looping over every item, they’re similar.

How do I convert a list to a set?

Call set(my_list). Use list(my_set) to go back, remembering the order may change.

Why can’t I put a list in a set?

Lists are mutable and unhashable. Convert them to tuples first.

How do I remove duplicates from a list but keep the order?

Use list(dict.fromkeys(my_list)).

Where are sets documented?

See Sets in the Python tutorial.