Sitelet https://www.askpython.com/python/set/python-set

Python Nested Sets: Create a Set of Groups

Grouping unordered collections in Python means choosing a representation that lets one collection hold the groups. A frozenset represents each group as an immutable set, and an outer set can store those groups.

I’ll show how to build and query this structure, then explain when a Counter is a better fit for repeated groups.

TL;DR

Convert each unordered inner group to a frozenset, then store those values in an outer set.

  • Use frozenset(row) to convert an iterable row.
  • The outer set supports membership and removes equal groups.
  • Choose a list or Counter when order or repeated counts matter.

What is a Python set of sets?

A Python set of sets represents each unordered group with frozenset, allowing the outer set to store groups and collapse equal ones.

Frozensets preserve unordered membership, so groups with the same values compare equal regardless of input order.

How to create and use a set of sets

Convert each group at the point where it enters the outer set, then query the resulting collection by converting the lookup group the same way. The diagram shows that conversion boundary.

Diagram showing input rows converted to frozenset values before collection in an outer set

Step 1: See why a mutable inner set fails

I ran the direct nesting attempt in nested_sets_demo.py, which printed the exact error before continuing.

try:
    invalid_groups = {{1, 2}, {3, 4}}
except TypeError as error:
    print(f"{type(error).__name__}: {error}")

The captured result is TypeError: unhashable type: ‘set’. The traceback names the invalid member type.

Step 2: Convert rows and test membership

Call frozenset() on each input row, then build the outer set with a comprehension. This works with row iterables such as lists and tuples. Strings are also iterable, so conversion treats each character as a separate member.

rows = [["red", "blue"], ["green"], ["blue", "red"]]
groups = {frozenset(row) for row in rows}
print(f"Unique groups: {len(groups)}")
print(f"Contains red/blue: {frozenset({'red', 'blue'}) in groups}")

The captured output from the conversion shows two distinct groups and a successful membership check:

Unique groups: 2
Contains red/blue: True
Terminal output demonstrating set conversion, membership, and frozenset operations

Step 3: Iterate through groups and their members

Loop over the outer set, then each inner frozenset. Neither iteration level promises an order. Sort values for stable display, and use a key that sorts each group.

for group in sorted(groups, key=lambda value: sorted(value)):
    print(sorted(group))

Step 4: Apply set operations to an inner group

Union, intersection, difference, and symmetric difference return new frozenset values. I ran three operators in the same demo to compare their results.

left = frozenset({1, 2, 3})
right = frozenset({3, 4})
print(f"Union: {left | right}")
print(f"Intersection: {left & right}")
print(f"Difference: {left - right}")

Measure the groups with len()

len(groups) counts distinct groups, and len(group) counts members in one group. Duplicate rows already collapsed during conversion do not count.

Combining inner members counts distinct values across groups.

groups = {frozenset({"red", "blue"}), frozenset({"green"})}
print(len(groups))
print(len(frozenset({"red", "blue"})))
print(len(set().union(*groups)))

For these values the counts are 2 groups, 2 members in the selected group, and 3 distinct values overall.

Edge cases and alternatives

Choose by whether groups need order, edits, or frequency counts.

RequirementRepresentationEffect
Unique unordered groupsSet of frozensetsEqual groups collapse
Editable groups in orderList of setsGroups and sequence remain mutable
Repeated unordered groups with countsCounter keyed by frozensetStores one frequency per group
Ordered values in each groupTuple keysDifferent order produces a different tuple

Empty groups and empty input

My run returned one empty group for two empty rows, and zero groups for empty input.

rows = [[], []]
print({frozenset(row) for row in rows})
print({frozenset(row) for row in []})

Choose a mutable or immutable outer collection

Freeze the outer layer too when the whole collection must be a dictionary key.

mutable_outer = {frozenset({"red", "blue"}), frozenset({"green"})}
immutable_outer = frozenset(mutable_outer)
lookup = {immutable_outer: "palette groups"}
print(lookup[immutable_outer])

Look up a member across all groups

To find a value anywhere, inspect or combine the inner groups.

groups = {frozenset({"red", "blue"}), frozenset({"green"})}
print(any("blue" in group for group in groups))
all_values = set().union(*groups)
print(all_values)

For example, this row fails because the list remains an unhashable member:

CaseSymptomFix
Row contains a listTypeError: unhashable type: ‘list’Use a tuple when its contents are hashable
Group membership must changefrozenset has no add or remove operationKeep editable sets in a list, or replace the entire frozenset
Group order mattersfrozenset does not retain sequence orderUse tuples or lists for each group

Count or combine groups instead

Counter keyed by frozenset retains frequencies for repeated unordered groups.

from collections import Counter

rows = [["red", "blue"], ["green"], ["blue", "red"]]
counts = Counter(frozenset(row) for row in rows)
print(counts[frozenset({"red", "blue"})])

For regular set methods, see AskPython’s guides to Python set union and Python set intersection. Its frozenset guide covers the constructor and additional operations.

Conclusion

For the exact type behavior, consult Python’s set types documentation. describes set and frozenset behavior, and the glossary definition of hashable explains the stable-hash requirement.

FAQ

These answers address common questions about nested groups.

Can a Python set contain a list?

No. A list is unhashable, so it cannot be a set member. Use a tuple or another hashable representation when that preserves the data’s meaning.

Can an outer frozenset contain frozensets?

Yes. Both the outer and inner frozensets are immutable, provided every nested member is hashable.

Does a set of frozensets keep duplicate groups?

No. Equal groups collapse in the outer set. Use a Counter keyed by frozenset to retain their counts.

Ninad
Ninad

A Python and PHP developer turned writer out of passion. Over the last 6+ years, he has written for brands including DigitalOcean, DreamHost, Hostinger, and many others. When not working, you'll find him tinkering with open-source projects, vibe coding, or on a mountain trail, completely disconnected from tech.

Articles: 136