python中提供了好用的数据结构,比如列表,字典和集合等。列表和字典是最常用的,而今天要分享的集合set也有独特的妙用。
1.set的特性
首先我们来看看集合的特性,
- 在集合中,所有元素都是不同
- 集合是无序,所以不可索引
- 集合和字字典一样都是都是hash存储,有利于查找
data = [1, 1, 1, 2, 3, 3, 3, 5]
print(set(data))
# {1, 2, 3, 5}
集合的常用操作有:
- 交集: 求公共部分
- 并集:合并两个集合,同时去重
- 差集:不同的部分
data = [1, 1, 1, 2, 3, 3, 3, 5]
data2 = [2, 2, 5]
set1 = set(data)
set2 = set(data2)
print("union:", set1.union(set2))
print("intersection:", set1.intersection(set2))
print("difference:", set1.difference(set2))
# union: {1, 2, 3, 5}
# intersection: {2, 5}
# difference: {1, 3}
2.set妙用场景一
如果有两个文件夹,我们想筛查出两个文件夹中共同的部分,应该怎么写这个过程?
import glob
dir_name1 = './test1/'
dir_name2 = './test2/'
file_list1 = glob.glob('{}/*'.format(dir_name1))
file_list2 = glob.glob('{}/*'.format(dir_name2))
ret = []
for file1 in file_list1:
for file2 in file_list2:
if file1 == file2:
ret.append(file1)
用列表来查找显然是效率低下的,时间复杂度O(N*M) N和M是列表的长度
另外一个用空间换时间,用字典
import glob
dir_name1 = './test1/'
dir_name2 = './test2/'
file_list1 = glob.glob('{}/*'.format(dir_name1))
file_list2 = glob.glob('{}/*'.format(dir_name2))
file_dict2 = { name: 0 for name in file_list2}
ret = []
for file1 in file_list1:
if file_dict2.get(file1) is not None:
ret.append(file1)
用字典的hash值直接查找效率是O(1), 只要扫一遍列表1, 复杂度为O(N)
如果用集合set呢?
import glob
dir_name1 = './test1/'
dir_name2 = './test2/'
file_list1 = glob.glob('{}/*'.format(dir_name1))
file_list2 = glob.glob('{}/*'.format(dir_name2))
ret = set(file_list1).union(file_list2)
更加简洁,时间复杂度平均为O(N+M)
3.set妙用场景二
set是hash结构存储的,所以只要set构建完成之后查找元素的效率是高于list的。
import random
import time
data3 = [i for i in range(100000000)]
t = time.time()
print(100000000 in data3)
print(time.time() - t)
# False
# 1.5218188762664795
set_data = set(data3)
t = time.time()
print(100000000 in set_data)
print(time.time() - t)
# False
# 0.0
上面的例子,印证了set的查询效率是高于list的;但是构建集合也是需要发时间的,所以比较适合频繁判断的情况(一次构建,多次查询)
希望set的妙用对你有帮助