摘要: 了解Python内置对象集合:它们是什么,如何创建它们,何时使用它们,内置函数,以及集合之间的关系操作。
原文:https://towardsdatascience.com/python-sets-and-set-theory-2ace093d1607
原文作者:Michael Galarnyk
翻译:老齐
列表和元组都是Python内置数据类型,它们按序列存储值。集合是另一种Python内置数据类型,它也可以存储值。主要的区别在于,集合与列表或元组不同,不能重复项,也不能存储无法排序的值。
由于集合不能有重复项,因此集合对于有效地从列表或元组中删除重复值以及执行常见的数学操作(如并集和交集)非常有用。
本文将向你介绍一些有关Python集合的内容:
好了,我们开始吧。
集合是中的值必须是唯一的、不可变的,且是无序的。
可以使用set()
创建空集合。
emptySet = set()
为了创建一个带有值的集合,可以将列表传递给set()
。
dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS']) dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])
如果查看上面dataScientist和dataEngineer变量,请注意集合中的值并没有按照添加的顺序排列。这是因为集合是无序的。
包含值的集合也可以使用大括号创建。
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'} dataEngineer = {'Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'}
请记住,大括号只能用于创建含有值的集合。下图显示,使用不带值的大括号是创建字典而不是集合。
要添加和移除值,首先必须创建集合。
# Initialize set with values graphicDesigner = {'InDesign', 'Photoshop', 'Acrobat', 'Premiere', 'Bridge'}
你可以使用add
方法向集合添加值。
graphicDesigner.add('Illustrator')
必须注意的是,你只能将不可变的值(如字符串或元组)添加到集合中。例如,如果你尝试将列表添加到集合中,则会收到TypeError这样的提醒。
graphicDesigner.add(['Powerpoint', 'Blender'])
有几种方法可以从集合中移除值。
**方法1:**你可以使用remove
方法从集合中移除值。
graphicDesigner.remove('Illustrator')
此方法的缺点是,如果尝试删除不在集合中的值,则会得到KeyError这样的提示。
**方法2:**可以使用discard
方法从集合中移除值。
graphicDesigner.discard('Premiere')
与remove
方法相比,这种方法的好处是:如果尝试删除不属于集合的值,则不会得到keyerror。如果你熟悉字典,你可能会发现它的工作方式与字典对象的get方法类似。
**方法3:**还可以使用pop
方法从集合中移除值并返回任意值。
graphicDesigner.pop()
需要注意的是,如果集合为空,该方法将导致KeyError。
你可以使用clear
方法从集合中移除所有值。
graphicDesigner.clear()
与许多Python内置数据类型一样,可以遍历一个集合。
# Initialize a set dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'}for skill in dataScientist: print(skill)
打印dataScientist中的每个值,请注意,在集合中打印的值不是按照它们被添加的顺序。这是因为集合是无序的。
本文强调集合是无序的。如果你发现需要以有序形式从集合中获取值,可以使用sorted
函数输出有序的列表。
type(sorted(dataScientist))
下面的代码按字母降序(本例中为Z-A)输出集合dataScientist中的值。
sorted(dataScientist, reverse = True)
本节的部分内容先前在《18个最常见的Python列表问题》中探讨过,但必须强调的是,集合是从列表中删除重复项的最快方法。为了说明这一点,让我们研究两种方法之间的性能差异。
**方法1:**使用集合从列表中删除重复项。
print(list(set([1, 2, 3, 1, 7])))
**方法2:**使用列表解析从列表中删除重复项。
def remove_duplicates(original): unique = [] [unique.append(n) for n in original if n not in unique] return (unique) print(remove_duplicates([1, 2, 3, 1, 7]))
可以使用timeit
库测量性能差异,该库允许你对Python代码计时。下面的代码为每个方法运行代码10000次,并输出它所用的总时间(秒)。
import timeit# Approach 1: Execution time print(timeit.timeit('list(set([1, 2, 3, 1, 7]))', number=10000))# Approach 2: Execution timeprint(timeit.timeit('remove_duplicates([1, 2, 3, 1, 7])', globals=globals(), number=10000))
比较这两种方法,可以发现使用集合来移除重复项更为有效。虽然这看起来只是时间上的一个小的差异,但如果你有非常大的列表,它可以为你节省很多时间。
集合在Python中的一个常见用法是进行数学运算,如并集、交集、差集和对称差集。下图显示了集合A和B上的两个数学运算。每个维恩图的红色部分是给定的集合运算的结果集。
Python集合有允许你执行这些数学操作的方法,以及提供等价结果的操作符。
在研究这些方法之前,让我们先创建两个集合dataScientist和dataEngineer。
dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'])dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])
集合dataScientist和dataEngineer的所有值组成的集合称为它们的并集,可以使用一个集合对象的union方法找出两个集合中的所有的惟一值。
# set built-in function uniondataScientist.union(dataEngineer)# Equivalent Result dataScientist | dataEngineer
unino
方法的返回值用可视化的方法表示就是下面的维恩图的红色部分。
两个集合dataScientist和dataEngineer的交集,表示为 dataScientist ∩ dataEngineer
。这个交集包含了所有既属于dataScientist又属于dataEngineer的值。
# Intersection operationdataScientist.intersection(dataEngineer)# Equivalent ResultdataScientist & dataEngineer
交集用可视化的方式表示为下面的维恩图的红色部分。
你可能会遇到这样一个情况:希望确保两个集合没有共同的值。换句话说,你想让两个集合的交集为空。这两个集合称为不相交集合。可以使用isdisjoint
方法测试不相交集。
# Initialize a setgraphicDesigner = {'Illustrator', 'InDesign', 'Photoshop'}# These sets have elements in common so it would return FalsedataScientist.isdisjoint(dataEngineer)# These sets have no elements in common so it would return TruedataScientist.isdisjoint(graphicDesigner)
你可能注意到,在下面的维恩图所显示的交集中,不相交集合dataScientist和graphicDesigner没有共同的值。
两个集合dataScientist和dataEngineer之间的差集是所有属于dataScientist 而不属于dataEngineer的值的集合。
# Difference OperationdataScientist.difference(dataEngineer)# Equivalent ResultdataScientist - dataEngineer
用可视化的方式表示差集,为下面的维恩图的红色部分。
两个集合dataScientist和dataEnngineer的对称差集,表示为dataScientist △ dataEngineer
,是属于这两个集合的其中之一的所有值的集合,但这些值不同时属于这两个集合。
# Symmetric Difference OperationdataScientist.symmetric_difference(dataEngineer)# Equivalent ResultdataScientist ^ dataEngineer
对称差集可以用可视化方式表示为下面的维恩图的红色部分。
你以前可能已经学习过列表解析、字典解析和生成器推解析。除了这些,还有集合解析,其方式如下:
{skill for skill in ['SQL', 'SQL', 'PYTHON', 'PYTHON']}
上面的输出是2个值的集合,因为集合不能有重复值。
使用集合解析背后的想法是让你用代码编写和推理,就像动手做数学一样。
{skill for skill in ['GIT', 'PYTHON', 'SQL'] if skill not in {'GIT', 'PYTHON', 'JAVA'}}
上面的代码类似于你之前所了解的差集。只是看起来有点不同。
成员检测即检查某个特定元素是否包含在一个序列中,例如字符串、列表、元组或集合。在Python中使用集合的一个主要优点是,它对于成员检测是高度优化的。例如,集合比列表更有效地进行成员检测。这是因为集合中的成员检测的平均时间复杂度与列表相比,是 O(1) vs O(n)。
下面的代码显示了一个使用列表的成员检测。
# Initialize a listpossibleList = ['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala']# Membership test'Python' in possibleList
使用集合也可以做类似的事情,更有效率。
# Initialize a setpossibleSet = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala'}# Membership test'Python' in possibleSet
因为possibleSet
是一个集合,而Python
是possibleSet
的一个值,所以可以将其表示为'Python' ∈ possibleSet
。
如果你有一个不属于这个集合的值,比如'Fortran'
,它将被表示为 'Fortran' ∉ possibleSet
。
理解成员关系的一个实际应用是子集。
我们先创建两个集合。
possibleSkills = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'} mySkills = {'Python', 'R'}
如果集合mySkills
的每个值也是possibleSkills
的值,那么mySkills
就是possibleSkills
的一个子集,在数学上写作mySkills ⊆ possibleSkills
。
你可以使用issubset
方法检查一个集合是否是另一个集合的子集。
mySkills.issubset(possibleSkills)
由于该方法在本例中返回True
,所以它是一个子集。在下面的维恩图中,请注意:集合mySkills
的每个值也是集合possibleSkills
的一个值。
你已经学习过嵌套列表和元组。
# Nested Lists and TuplesnestedLists = [['the', 12], ['to', 11], ['of', 9], ['and', 7], ['that', 6]]nestedTuples = (('the', 12), ('to', 11), ('of', 9), ('and', 7), ('that', 6))
嵌套集合的问题是,你通常不能使用嵌套集合,因为集合不能包括可变值。
只有在一种情况下,你可能希望使用不可变集合。不可变集合与集合非常相似,只是它不可变。
你可以使用frozenset()
生成一个不可变集合。
# Initialize a frozensetimmutableSet = frozenset()
如果使用不可变集合,则可以生成嵌套集合。
nestedSets = set([frozenset()])
重要的是要记住,不可变集合的一个主要缺点是:由于它是不可变的,这就意味着不能添加或删除值。
Python集合对于有效地从序列(如列表)中移除重复值以及执行常见的数学操作(如并集和交集)非常有用。人们经常遇到的一些挑战是何时使用各种数据类型。例如,如果你不确定何时使用字典比使用集合有利,我建议你认真阅读 《Python大学实用教程》 或者 《跟老齐学Python:轻松入门》 ,这两本书都是由电子工业出版社出版,书中的详细讲解和案例能够让你理解各种对象类型的应用场景。
(点击下面的“阅读原文”,京东双十一优惠购买上述图书)