当前位置:

首页 > 编程开发 > Python基础指南之集合set的创建与自动去重详解

Python基础指南之集合set的创建与自动去重详解

集合是Python内置容器类型,具有元素唯一、无序和可变特性。创建可用花括号或set()构造函数,自动去重基于哈希表和相等性比较,增删改操作包括add、remove、discard、pop等。集合成员检测时间复杂度为O(1),适用于高效去重和成员检测场景。

聊聊集合(set)——这个数据类型在Python里其实挺“特立独行”的。

先看一个生活中常见的场景:你手里有一份包含1000条用户访问记录的文件,现在想知道到底有多少个不同的IP访问了你的网站。如果只会用列表,你得写一个循环,逐一判断每个IP是否已经记录过,代码笨重且低效。

Python基础指南之集合set的创建与自动去重详解

但如果用Python的集合(set),一行代码就搞定了:

ip_list = ['192.168.1.1', '10.0.0.5', '192.168.1.1', '172.16.0.3', '10.0.0.5']
unique_ips = set(ip_list)
print(unique_ips)  # {'192.168.1.1', '10.0.0.5', '172.16.0.3'}
print(f'独立IP数量: {len(unique_ips)}')  # 3

集合是Python内置的四大核心容器类型之一(列表、元组、字典、集合)。它有两个最独特的天性:元素不重复无序性。这两个特性让它成为去重、成员检测、集合运算(交并差)的最佳选择。

今天这篇文章,我们来深入拆解集合的创建方式和自动去重特性。下一篇我们会讲集合的交并差运算。

二、集合的基本概念

2.1 什么是集合?

集合就是一个无序的、元素唯一的容器。它和数学里的“集合”概念一脉相承——集合中的元素不能重复,而且“{1, 2}”和“{2, 1}”是同一个集合(因为没有顺序)。

# 集合的三个核心特征
# 1. 元素唯一(自动去重)
s = {1, 2, 2, 3, 3, 3}
print(s)  # {1, 2, 3}——重复的2和3被自动去掉了

# 2. 无序——元素的存储顺序和插入顺序无关
s = {3, 1, 4, 1, 5, 9, 2, 6}
print(s)  # 输出顺序通常不是你插入的顺序

# 3. 可变——可以添加和删除元素(但元素本身必须是不可变的)
s = {1, 2, 3}
s.add(4)      # ✅ 可以添加
s.remove(1)   # ✅ 可以删除
print(s)      # {2, 3, 4}

2.2 集合在Python类型体系中的位置

集合和列表、字典一样是可变类型。但集合中的元素必须是不可变(可哈希)类型。这意味着:

# ✅ 这些可以放进集合——都是不可变类型
valid_set = {1, 3.14, 'hello', (1, 2), True, None, frozenset([1, 2])}
print(valid_set)

# ❌ 这些不能放进集合——是可变类型
# {[1, 2]}      # TypeError: unhashable type: 'list'
# {{'a': 1}}    # TypeError: unhashable type: 'dict'
# {{1, 2}}      # TypeError: unhashable type: 'set'(除非用frozenset)

这和字典的“键”的要求是一样的——因为集合底层也是基于哈希表实现的,和字典共用同一套数据结构。

2.3 集合 vs 列表 vs 字典

特性列表(list)字典(dict)集合(set)
元素唯一❌ 可重复✅ 键唯一✅ 元素唯一
有序性✅ 有序✅ 保序(3.7+)❌ 无序
可变性✅ 可变✅ 可变✅ 可变
索引访问lst[0]d[key]❌ 不支持
查找速度O(n)O(1)O(1)
底层结构动态数组哈希表哈希表

三、创建集合的N种方式

3.1 花括号直接创建

# 最基本的方式——用花括号
fruits = {'apple', 'banana', 'orange'}
print(fruits)  # {'banana', 'orange', 'apple'}
print(type(fruits))  # 

# 空集合——⚠️ 必须用set(),因为{}是空字典!
empty_set = set()
print(type(empty_set))  # 

empty_dict = {}
print(type(empty_dict))  # ——注意区别!

# 集合中的元素自动去重
numbers = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}
print(numbers)  # {1, 2, 3, 4}
print(len(numbers))  # 4(不是10)

3.2 set()构造函数——从任何可迭代对象创建

# set()接受任何可迭代对象

# 从列表创建
s1 = set([1, 2, 3, 2, 1])
print(s1)  # {1, 2, 3}

# 从元组创建
s2 = set((10, 20, 30, 20))
print(s2)  # {10, 20, 30}

# 从字符串创建——每个字符成为一个元素
s3 = set('hello world')
print(s3)  # {'h', 'e', 'l', 'o', ' ', 'w', 'r', 'd'}
# 注意:两个'l'和两个'o'各只保留一个

# 从range对象创建
s4 = set(range(10))
print(s4)  # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

# 从字典创建(取键)
s5 = set({'a': 1, 'b': 2, 'c': 3})
print(s5)  # {'a', 'b', 'c'}

# 从生成器表达式创建
s6 = set(x ** 2 for x in range(5))
print(s6)  # {0, 1, 4, 9, 16}

# 从文件对象创建(每行一个元素)
# with open('file.txt') as f:
#     lines = set(f)  # 自动去重的行集合

3.3 创建包含各种类型元素的集合

# 混合类型集合
mixed = {42, 'hello', 3.14, True, None, (1, 2)}
print(mixed)  # {False, 3.14, 'hello', 42, None, (1, 2)}

# ⚠️ 注意:True在集合中等于1,False等于0
# 因为bool是int的子类,True==1, False==0
numbers_with_bool = {1, True, 2, False, 0, 3}
print(numbers_with_bool)  # {0, 1, 2, 3}——True和1合并了,False和0合并了

# 验证
print(True == 1)   # True
print(False == 0)  # True
print({1, True})   # {1}——因为是同一个值
print({0, False})  # {0}——同理

四、自动去重特性的深度理解

4.1 去重的依据:hash__和__eq

集合判断两个元素是否“相同”,依据的是哈希值和相等性比较:

# 去重流程:
# 1. 计算新元素的哈希值 hash(element)
# 2. 找到哈希表中对应位置
# 3. 如果该位置已有元素,用 == 比较
# 4. 如果相等,则不插入(去重)
# 5. 如果不等(哈希冲突),用开放地址法探测下一个位置

# 演示:自定义类的去重行为
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __hash__(self):
        """定义哈希值——基于name"""
        return hash(self.name)
    
    def __eq__(self, other):
        """定义相等性——基于name和age"""
        if not isinstance(other, Person):
            return False
        return self.name == other.name and self.age == other.age
    
    def __repr__(self):
        return f'Person({self.name}, {self.age})'


# 哈希相同但==不相等 → 两个元素都保留(哈希冲突)
p1 = Person('Alice', 25)  # hash基于'Alice'
p2 = Person('Alice', 30)  # hash还是基于'Alice',但age不同
s = {p1, p2}
print(s)  # {Person(Alice, 25), Person(Alice, 30)}——两个都保留

# 哈希相同且==相等 → 去重
p3 = Person('Alice', 25)  # 和p1一模一样
p4 = Person('Alice', 25)  # 也和p1一模一样
s2 = {p1, p3, p4}
print(s2)  # {Person(Alice, 25)}——只有一个

4.2 各种类型的去重行为

# 整数——按数值去重
s = {1, 2, 3, 1, 2}
print(s)  # {1, 2, 3}

# 浮点数——按数值去重
s = {1.0, 2.0, 1.0, 3.0}
print(s)  # {1.0, 2.0, 3.0}

# ⚠️ 注意:1和1.0在集合中是一样的!
s = {1, 1.0, 2, 3}
print(s)  # {1, 2, 3}——1和1.0被视为相同
print(1 == 1.0)  # True
print(hash(1))   # 1
print(hash(1.0)) # 1——相同的哈希值!

# 字符串——按内容去重
s = {'hello', 'world', 'hello', 'HELLO'}
print(s)  # {'hello', 'world', 'HELLO'}——'hello'被去重,'HELLO'不同

# 元组——按内容去重
s = {(1, 2), (3, 4), (1, 2), (2, 1)}
print(s)  # {(1, 2), (3, 4), (2, 1)}——(1,2)去重,(2,1)是不同元组

# None——只有一个None
s = {None, None, None}
print(s)  # {None}

4.3 去重的实际性能

集合的去重依赖哈希表,查询和插入的平均时间复杂度都是O(1),所以大批量数据的去重非常快:

import time
import random

# 生成10万个有重复的整数
data = [random.randint(1, 10000) for _ in range(100000)]

# 方法一:手动去重(用列表 + in 检查)
start = time.perf_counter()
unique_list = []
for x in data:
    if x not in unique_list:  # O(n)每次
        unique_list.append(x)
print(f'手动去重: {time.perf_counter() - start:.4f}s,结果数量: {len(unique_list)}')

# 方法二:用集合去重
start = time.perf_counter()
unique_set = set(data)  # O(1)每次,总共O(n)
print(f'集合去重: {time.perf_counter() - start:.4f}s,结果数量: {len(unique_set)}')

# 性能差异通常有数百倍到数千倍!

五、集合的增删改操作

虽然我们后面会详细讲集合操作,但这里先快速了解一下基本增删:

5.1 添加元素

s = {1, 2, 3}

# add()——添加单个元素
s.add(4)
print(s)  # {1, 2, 3, 4}

# 添加重复元素——静默忽略,不报错
s.add(4)
print(s)  # {1, 2, 3, 4}——还是原来的样子

# update()——批量添加(从可迭代对象)
s.update([5, 6, 7])
print(s)  # {1, 2, 3, 4, 5, 6, 7}

s.update({8, 9}, (10, 11))
print(s)  # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}

# update也可以接受字符串(逐个字符添加)
s2 = set()
s2.update('abc')
print(s2)  # {'a', 'b', 'c'}

5.2 删除元素

s = {1, 2, 3, 4, 5}

# remove()——删除指定元素,不存在则报错
s.remove(3)
print(s)  # {1, 2, 4, 5}
# s.remove(99)  # KeyError: 99

# discard()——删除指定元素,不存在也不报错
s.discard(4)
print(s)  # {1, 2, 5}
s.discard(99)  # 不报错

# pop()——随机删除并返回一个元素
# ⚠️ 注意:集合无序,pop()删除的是"任意"一个元素
popped = s.pop()
print(f'弹出: {popped}, 剩余: {s}')

# clear()——清空集合
s.clear()
print(s)  # set()

5.3 删除操作的对比表

方法行为元素不存在时返回值
remove(x)删除xKeyErrorNone
discard(x)删除x不报错None
pop()删除任意一个KeyError(集合为空)被删除的元素
clear()删除所有不报错None

六、集合的成员检测和遍历

6.1 成员检测——O(1)的查找速度

# 集合最大的性能优势:成员检测是O(1)
# 列表的成员检测是O(n),集合是O(1)

s = set(range(100000))

import time

# 集合查找
start = time.perf_counter()
for _ in range(1000):
    _ = 99999 in s
print(f'集合in: {time.perf_counter() - start:.6f}s')

# 列表查找(对比)
lst = list(range(100000))
start = time.perf_counter()
for _ in range(1000):
    _ = 99999 in lst
print(f'列表in: {time.perf_counter() - start:.6f}s')

# 实际示例:快速过滤
all_users = {'alice', 'bob', 'charlie', 'da vid', 'eve', 'frank', 'grace'}
vip_users = {'alice', 'charlie', 'grace'}

# 检查是否是VIP——O(1)
print('alice' in vip_users)    # True
print('bob' in vip_users)      # False

# 检查是否有访问权限
def has_access(username):
    return username in all_users

print(has_access('hacker'))  # False

6.2 遍历集合

s = {'apple', 'banana', 'orange', 'grape', 'mango'}

# for循环遍历——顺序不保证!
print('遍历集合:')
for fruit in s:
    print(f'  {fruit}', end='')
print()

# 排序后遍历
print('排序后遍历:')
for fruit in sorted(s):
    print(f'  {fruit}', end='')
print()

# 按长度排序遍历
print('按长度排序:')
for fruit in sorted(s, key=len):
    print(f'  {fruit}({len(fruit)})', end='')
print()

# enumerate遍历(带序号)
print('带序号遍历:')
for i, fruit in enumerate(s, 1):
    print(f'  {i}. {fruit}')

# ⚠️ 遍历时不能修改集合!
# for item in s:
#     s.add('new')  # RuntimeError: Set changed size during iteration

七、集合的常用内置操作

7.1 基础信息操作

s = {1, 2, 3, 4, 5}

# len()——元素个数
print(len(s))  # 5

# max() / min()——最大/最小元素
print(max(s))  # 5
print(min(s))  # 1

# sum()——求和
print(sum(s))  # 15

# any() / all()
print(any({0, False, 1}))  # True(至少有一个为真)
print(all({1, True, 2}))   # True(全部为真)
print(all({0, 1, 2}))      # False(0为假)

7.2 集合之间的关系判断

a = {1, 2, 3}
b = {1, 2, 3, 4, 5}
c = {1, 2, 3}

# 判断子集
print(a.issubset(b))      # True——a是b的子集
print(a <= b)             # True——运算符写法
print(a < b)              # True——真子集(a⊂b,不等于b)

# 判断超集
print(b.issuperset(a))    # True——b是a的超集
print(b >= a)             # True——运算符写法
print(b > a)              # True——真超集

# 判断相等(内容相同)
print(a == c)             # True
print(a == b)             # False

# 判断不相交
d = {4, 5, 6}
print(a.isdisjoint(d))    # True——没有公共元素
print(a.isdisjoint(b))    # False——有公共元素(1,2,3)

八、实战场景

8.1 场景一:数据去重与清洗

# 场景:从用户行为日志中提取不同的操作类型
log_entries = [
    'LOGIN - alice',
    'LOGOUT - alice',
    'LOGIN - bob',
    'PURCHASE - alice',
    'LOGIN - alice',      # 重复操作
    'VIEW_PAGE - charlie',
    'LOGIN - bob',         # 重复操作
    'PURCHASE - bob',
    'VIEW_PAGE - alice',
    'LOGOUT - bob',
]

# 提取所有不同的操作类型
action_types = {entry.split(' - ')[0] for entry in log_entries}
print(f'操作类型: {action_types}')
# {'LOGIN', 'LOGOUT', 'PURCHASE', 'VIEW_PAGE'}

# 提取所有不同的用户
users = {entry.split(' - ')[1] for entry in log_entries}
print(f'活跃用户: {users}')
# {'alice', 'bob', 'charlie'}

8.2 场景二:成员白名单/黑名单

# 场景:API接口的IP黑白名单
class IPFilter:
    """IP黑白名单过滤器——用集合实现O(1)查找"""
    
    def __init__(self):
        self._whitelist = set()  # 白名单(优先)
        self._blacklist = set()  # 黑名单
    
    def add_whitelist(self, ip):
        self._whitelist.add(ip)
    
    def add_blacklist(self, ip):
        self._blacklist.add(ip)
    
    def remove_whitelist(self, ip):
        self._whitelist.discard(ip)
    
    def remove_blacklist(self, ip):
        self._blacklist.discard(ip)
    
    def is_allowed(self, ip):
        """判断IP是否允许访问"""
        # 白名单优先——白名单中的IP即使同时在黑名单中也允许
        if ip in self._whitelist:
            return True
        # 在黑名单中
        if ip in self._blacklist:
            return False
        # 都不在——默认允许
        return True
    
    def load_from_file(self, filename, list_type):
        """从文件加载IP列表"""
        target = self._whitelist if list_type == 'whitelist' else self._blacklist
        with open(filename) as f:
            for line in f:
                ip = line.strip()
                if ip:
                    target.add(ip)
        print(f'已加载 {len(target)} 个IP到{list_type}')


# 使用示例
ip_filter = IPFilter()
ip_filter.add_blacklist('10.0.0.99')
ip_filter.add_blacklist('192.168.1.100')
ip_filter.add_whitelist('10.0.0.1')  # 管理员IP,始终允许

# 检查
print(ip_filter.is_allowed('10.0.0.99'))     # False——黑名单
print(ip_filter.is_allowed('10.0.0.1'))      # True——白名单优先
print(ip_filter.is_allowed('172.16.0.5'))    # True——不在任何名单中

8.3 场景三:文本分析——找出不重复的单词

# 场景:分析两篇文章的词汇差异
article1 = """
Machine learning is a subset of artificial intelligence that enables
systems to learn and improve from experience without being explicitly
programmed machine learning focuses on the development of computer
programs that can access data and use it to learn for themselves
"""

article2 = """
Deep learning is a subset of machine learning in artificial intelligence
that has networks capable of learning unsupervised from data that is
unstructured or unlabeled deep learning is also known as deep neural
network learning
"""

# 提取单词集合
def extract_words(text):
    return {word.strip('.,;:!?()[]{}'"').lower() for word in text.split() if len(word) > 1}

words1 = extract_words(article1)
words2 = extract_words(article2)

print(f'文章1不同单词数: {len(words1)}')
print(f'文章2不同单词数: {len(words2)}')

# 文章1独有的单词
only_in_1 = words1 - words2
print(f'n文章1独有的词 ({len(only_in_1)}个): {only_in_1}')

# 文章2独有的单词
only_in_2 = words2 - words1
print(f'文章2独有的词 ({len(only_in_2)}个): {only_in_2}')

# 两篇文章共有的单词
common = words1 & words2
print(f'两篇共有的词 ({len(common)}个): {common}')

# 所有出现过的单词
all_words = words1 | words2
print(f'总词汇量: {len(all_words)}')

8.4 场景四:快速统计不同元素

# 场景:统计一个论坛帖子里有多少不同的参与者
# 包括发帖人和所有回复人

posts = [
    {'author': 'alice', 'replies': ['bob', 'charlie', 'bob']},
    {'author': 'bob', 'replies': ['alice', 'da vid']},
    {'author': 'charlie', 'replies': ['alice', 'eve', 'alice', 'da vid']},
    {'author': 'da vid', 'replies': ['eve']},
]

# 统计所有参与者(去重)
all_participants = set()
for post in posts:
    all_participants.add(post['author'])      # 发帖人
    all_participants.update(post['replies'])  # 回复人

print(f'参与者总数: {len(all_participants)}')
print(f'参与者名单: {all_participants}')

# 统计谁发了帖(有帖子但没回复?)
authors = {post['author'] for post in posts}
repliers = set()
for post in posts:
    repliers.update(post['replies'])

print(f'只发帖没回复的人: {authors - repliers}')
print(f'只回复没发帖的人: {repliers - authors}')
print(f'又发帖又回复的人: {authors & repliers}')

九、集合的底层原理简述

9.1 哈希表

集合底层和字典一样,使用哈希表。每个元素通过哈希函数计算出一个整数,这个整数决定了元素在哈希表中的存储位置:

# 查看元素的哈希值
print(hash('hello'))   # 某个整数(每次运行可能不同)
print(hash(42))        # 42(整数的哈希就是自己)
print(hash((1, 2, 3))) # 某个整数

# 哈希表的工作流程:
# 1. 对元素x计算 hash(x)
# 2. 用 hash(x) % table_size 确定存储槽位
# 3. 如果槽位为空,直接存储
# 4. 如果槽位已被占用(哈希冲突),用开放地址法探测下一个位置
# 5. 如果发现相等的元素(__eq__返回True),则不插入(去重)

9.2 为什么集合是无序的

# 集合的无序不是"随机",而是"按哈希值分布"
# 元素的存储位置由哈希值决定,不是插入顺序

s = set()
s.add(1)
s.add(2)
s.add(3)
print(s)  # 输出顺序通常看起来"有序",是因为小整数的哈希就是自己

# 但对字符串就不一定了
s = {'banana', 'apple', 'cherry'}
print(s)  # 输出顺序不可预测

# ⚠️ 如果你需要保序的集合,可以:
# 1. 使用字典的键(Python 3.7+保序)
ordered_unique = dict.fromkeys([3, 1, 4, 1, 5, 9, 2, 6])
print(list(ordered_unique))  # [3, 1, 4, 5, 9, 2, 6]——保序去重

# 2. 使用sorted()排序输出
print(sorted(s))  # ['apple', 'banana', 'cherry']——字母序

9.3 集合的内存占用

import sys

# 集合有一定的内存开销(维护哈希表)
numbers = list(range(1000))
lst = numbers
s = set(numbers)

print(f'列表内存: {sys.getsizeof(lst)} 字节')
print(f'集合内存: {sys.getsizeof(s)} 字节')
# 集合通常占用更多内存——这是哈希表结构的代价
# 换取的是O(1)的查找和去重能力

# 实际内容的内存还包括元素本身
# sys.getsizeof只测量容器对象本身
# 如果需要精确测量,可以用更专业的工具

十、常见陷阱与注意事项

10.1 陷阱一:空集合用{}是错的

# ❌ 这不是空集合!
empty = {}
print(type(empty))  # ——这是字典!

# ✅ 这才是空集合
empty_set = set()
print(type(empty_set))  # 

# 为什么?因为Python用{}初始化空字典的历史更早
# set字面量语法是后来添加的,必须避免歧义

10.2 陷阱二:可变元素不能放入集合

# ❌ 列表不能放入集合
# s = {[1, 2, 3]}  # TypeError: unhashable type: 'list'

# ❌ 字典不能放入集合
# s = {{'a': 1}}   # TypeError: unhashable type: 'dict'

# ❌ 集合不能放入集合
# s = {{1, 2}}     # TypeError: unhashable type: 'set'

# ✅ 但可以用frozenset
s = {frozenset([1, 2]), frozenset([3, 4])}
print(s)  # {frozenset({1, 2}), frozenset({3, 4})}

# ❌ 包含可变元素的元组也不能放入集合
# s = {(1, [2, 3])}  # TypeError: unhashable type: 'list'
# 因为元组中的列表是可变的,导致整个元组不可哈希

# ✅ 纯不可变元素的元组可以
s = {(1, 2), (3, 4)}
print(s)  # {(1, 2), (3, 4)}

10.3 陷阱三:遍历时修改集合

s = {1, 2, 3, 4, 5}

# ❌ 遍历时修改集合——会引发RuntimeError
# for x in s:
#     if x % 2 == 0:
#         s.remove(x)  # RuntimeError: Set changed size during iteration

# ✅ 正确方式一:遍历副本
for x in s.copy():
    if x % 2 == 0:
        s.remove(x)
print(s)  # {1, 3, 5}

# ✅ 正确方式二:用集合推导式创建新集合
s = {1, 2, 3, 4, 5}
s = {x for x in s if x % 2 != 0}
print(s)  # {1, 3, 5}

# ✅ 正确方式三:先收集要删除的,再统一删
s = {1, 2, 3, 4, 5}
to_remove = {x for x in s if x % 2 == 0}
s -= to_remove
print(s)  # {1, 3, 5}

10.4 陷阱四:集合是不可索引的

s = {10, 20, 30, 40, 50}

# ❌ 集合不支持索引访问
# print(s[0])  # TypeError: 'set' object is not subscriptable

# ❌ 集合不支持切片
# print(s[1:3]) # TypeError

# 如果你需要"第n个元素"——先转为列表
# 但注意:转为列表后的顺序不确定!
lst = list(s)
print(lst[0])  # 可以访问,但不知道是哪个元素

# 如果需要有序集合,用sorted
for i, item in enumerate(sorted(s)):
    print(f'{i}: {item}')

10.5 陷阱五:True和1、False和0的混淆

# ⚠️ 在集合中,True==1,False==0
s = {1, True, 0, False}
print(s)  # {0, 1}——只有两个元素

# 含义:True和1在集合中被视为同一个值
# 同理False和0也被视为同一个值
# 这是因为 bool 是 int 的子类

# 验证
print(issubclass(bool, int))  # True
print(True == 1)              # True
print(False == 0)             # True
print(hash(True))             # 1
print(hash(1))                # 1
print(hash(False))            # 0
print(hash(0))                # 0

十一、集合 vs 列表:什么时候用哪个

# 选型决策树
def choose_collection(requirements):
    """
    根据需求选择合适的集合类型
    """
    needs_order = requirements.get('order')      # 需要保持顺序
    needs_unique = requirements.get('unique')    # 需要唯一性
    needs_index = requirements.get('index')      # 需要按位置访问
    needs_search = requirements.get('search')    # 需要快速查找
    needs_modify = requirements.get('modify')    # 需要频繁修改
    
    if needs_unique and needs_search:
        if needs_order:
            return 'dict(Python 3.7+保序,键唯一,用作有序集合)'
        return 'set'  # 去重 + 快速查找
    elif needs_order and needs_index:
        return 'list'  # 保序 + 索引访问
    elif needs_unique and needs_order:
        return 'OrderedDict的键 或 dict.fromkeys()'
    else:
        return '根据具体情况选择'


# 示例
print(choose_collection({'unique': True, 'search': True}))
# set

print(choose_collection({'order': True, 'index': True}))
# list

print(choose_collection({'unique': True, 'order': True}))
# dict(Python 3.7+)

十二、本篇小结

集合是Python中专门用于去重快速查找的数据结构:

核心特性:

  • 元素唯一:自动去重(基于__hash____eq__
  • 无序:存储顺序由哈希值决定,不保证插入顺序
  • 可变:可以add、remove(但元素本身必须是不可变的)
  • O(1)查找:成员检测(in)极快

创建方式:

  • {1, 2, 3}——花括号直接创建(空集合必须用set()
  • set(iterable)——从任何可迭代对象创建
  • 集合推导式:{x for x in iterable if condition}

常用操作:

  • 增:add()(单个)、update()(批量)
  • 删:remove()(不存在报错)、discard()(不存在不报错)、pop()(随机删一个)、clear()
  • 查:in(O(1)成员检测)
  • 判断:issubset()issuperset()isdisjoint()

掌握集合的创建和去重特性后,下一篇我们将深入学习集合最强大的能力——交并差对称差运算。这些集合运算在数据处理、权限管理、图算法等领域有着极其广泛的应用。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发 Python
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

Python安装后怎么打开:使用IDLE或命令行启动解释器
Python安装后怎么打开:使用IDLE或命令行启动解释器

刚在Windows安装好Python却不知道如何启动?本文详细演示如何通过开始菜单找到并打开IDLE集成开发环境,以及如何在PowerShell或命令提示符中使用python和py命令启动交互式解释器、运行.py脚本文件。包含退出解释器的方法及常见启动问题排查,帮助初学者快速验证安装成功并开始编写代码。

Windows系统Python安装教程:下载、勾选PATH及环境变量配置
Windows系统Python安装教程:下载、勾选PATH及环境变量配置

针对Windows初学者的Python安装实战指南。详细讲解如何从Python官网下载匹配架构的安装包,重点演示安装首屏勾选“Add python.exe to PATH”的关键操作,并提供使用python --version和py命令验证环境变量的具体步骤,帮助新手快速搭建开发环境并排查路径问题。

麒麟OS如何查看Python进程的运行状态
麒麟OS如何查看Python进程的运行状态

要想确认麒麟OS中Python程序的运行状态以及资源占用情况,我们可以这样做:用ps -ef | grep python来筛选进程;通过top命令,按P键排序查看实时负载;使用pgrep -f "script.py"精准获取PID;借助lsof -p PID验证文件打开状态。另外,还可以结合syst

Python在Debian上如何配置SSL证书
Python在Debian上如何配置SSL证书

在Debian系统上配置SSL证书通常涉及以下几个步骤:安装Web服务器:首先,你需要一个Web服务器,比如Apache或Nginx。这里以Apache为例。sudo apt updatesudo apt install apache2获取SSL证书:你可以从Let’s Encrypt免费获取SSL

统信UOS怎么安装Python开发环境
统信UOS怎么安装Python开发环境

要想让Python项目在统信UOS上正常运行,得先安装python3、python3-pip、python3-venv、python3-dev以及build-essential等组件。具体操作就是执行sudo apt install命令来一步到位完成安装,同时别忘了配置清华镜像源来给pip加速哦。在

纯Python方案实现中英文全文搜索
纯Python方案实现中英文全文搜索

在互联网上的各类网站中,无论大小,基本上都会有一个搜索框,用来给用户对内容进行搜索,小到站点搜索,大到搜索引擎搜索。从简单的来说,搜索功能确实很简单,一个简单的select语句就可以实现数据的搜索。而从复杂的来看,无论是搜索的精度还是搜索的效率,都是有很深的研究范围的。对于简单的搜索功能来说,一个s

Mac如何取消通过Python脚本运行的关机程序
Mac如何取消通过Python脚本运行的关机程序

立即在终端输入sudo shutdown -c取消倒计时关机,成功后显示“Shutdown cancelled”;若存在pmset重复任务,需再执行sudo pmset repeat cancel清除。Mac因Python脚本执行了os.system("sudo shutdown -h +10")或

Pythonasyncio异步并发与多固定出口IP调度实战
Pythonasyncio异步并发与多固定出口IP调度实战

之前写过一篇同步场景下用 Python 管理多个固定出口 IP 的实践(ExitPool + requests/httpx),覆盖了健康检查、故障转移和连接池复用。但在实际业务中,越来越多的场景用 asyncio 做高并发采集或批量接口调用——异步事件循环下多出口的管理方式和同步场景完全不同:单线程

Python在静态出口IP产品中的实战:从地址漂移巡检到多IP故障切换
Python在静态出口IP产品中的实战:从地址漂移巡检到多IP故障切换

写在前面:为什么静态出口 IP 不是"买了就行"不少团队在引入静态出口 IP 产品时,第一反应往往是:“地址配上去,这事就算完了。”可真到了真实业务里,静态出口 IP 真正能体现价值的地方,往往不在分配这一步,而在分配之后怎么管:地址有没有漂移,质量是否达标,某一条线路突然不可用时怎么切换,连接层又

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。