基于股票大数据分析的Python入门实战(视频教学版)
上QQ阅读APP看书,第一时间看更新

2.2 集合可以去除重复元素

Python语言中的集合(Set)是无法包含重复元素的,所以在实际应用中,经常通过集合来执行去重操作。此外,在数据分析等应用场景中,还可以使用集合包含的各种操作方法,比如union(并集)、intersection(交集)和difference(差集)。

2.2.1 通过集合去掉重复的元素

在下面的SetRemoveDup.py范例程序中演示了集合的常见用法,可以从中看到集合具有自动去掉重复元素的功能。

1    # !/usr/bin/env python
2    # coding=utf-8
3    # 调用集合的方法把列表转换成集合
4    set1=set(["a", "a", "b", "b", "c"])
5    print(set1) # 输出set(['a', 'c', 'b'])
6    # 添加元素
7    set1.add("d")
8    set1.add("c")         # 由于重复,因此无法添加
9    print(set1)         # set(['a', 'c', 'b', 'd'])
10    
11    set2=set1.copy()
12    set1.clear()
13    print(set1)     # 由于已清空,因此输出set([])
14    print(set2)     # set(['a', 'c', 'b', 'd'])
15    
16    set2.discard("f") # 删除元素,哪怕没找到也不会抛出异常
17    
18    list=[1,1,2,2,3,3,4,4,5]     # 含重复元素的列表
19    setFromList=set(list)        # 通过集合去掉重复的元素
20    print(setFromList)           # 输出为set([1, 2, 3, 4, 5])

在第4行中通过调用set方法,把一组包含重复字母的列表转换成集合元素,从第5行的打印语句可知,在set1中,已经没有重复元素了,由此能体会到集合的去除重复元素的特性。

在第7行和第8行中,调用add方法向set1中添加元素,由于已经有了c这个字母,因此无法再插入重复的元素。在第11行和第12行中,可以看到常用于集合的copy和clear方法。

在第16行中,调用discard方法来去掉集合中的元素,该方法也适用于列表(List)。与之前提到的remove方法不同,调用这个方法删除元素时,哪怕元素不存在,也不会抛出异常。

在第18行和第19行中演示了集合的常规做法,即去掉列表中的重复元素。和第4行程序语句去重复功能不同的是,这里是通过列表保存了一份去重复前的原始数据,这样哪怕对去重复后的数据操作有误,也能通过原始数据进行恢复。

2.2.2 常见的集合操作方法

在数据统计和分析场景里,经常会对不同的对象进行各种集合操作,比如交集、并集和差集等,通过集合提供的方法,可以比较便捷地实现这一功能。在下面的SetHandleData.py范例程序中演示了集合的各种操作。

1    # !/usr/bin/env python
2    # coding=utf-8
3    # 以大括号的方式定义集合
4    set1={'1', '3', '5', '7'}
5    set2={'2', '3', '6', '7'}
6    # 不能用中括号的方式定义集合,例如 set1=['1', '3', '5', '7']
7    # 交集
8    set3=set1 & set2
9    print(set3)             # 输出 set(['3', '7'])
10    print(set1 & set2)         # 输出 set(['3', '7'])
11    print(set1.intersection(set2)) # 输出 set(['3', '7'])
12    # 并集
13    set4=set1 | set2
14    print(set4)                 # 输出set(['1', '3', '2', '5', '7', '6'])
15    print(set1 | set2)             # set(['1', '3', '2', '5', '7', '6'])
16    print(set1.union(set2))     # set(['1', '3', '2', '5', '7', '6'])
17    # 差集
18    print(set1 - set2)                # 输出set(['1', '5'])
19    print(set1.difference(set2))    # 输出set(['1', '5'])
20    print(set2 - set1)                # 输出set(['2', '6'])
21    print(set2.difference(set1))      # 输出set(['2', '6'])
22    # 演示不可变集合的特性
23    unChangedSet=frozenset(3.14,9.8)
24    # unChangedSet.add(2.718)
25    # unChangedSet[0]=2.718
26    # unChangedSet.discard(3.14)

之前提到,定义列表时用方括号,定义元组时用小括号,定义集合对象时,要像第4行和第5行中那样通过大括号。这里请注意,如果像第6行那样,通过方括号定义的是列表,那么列表类对象是无法参与后面的各种针对集合的操作的。

从第8行到第11行的程序语句演示了集合交集的操作,具体可以像第8行和第10行程序语句那样使用“&”运算符,也可以像第11行那样通过调用intersection方法来求交集。通过打印语句可以看到,返回的结果是set1和set2中都有的元素,即交集,由此能验证求交集的结果。而从第13行到第16行的程序语句是使用“|”运算符和调用union方法来求并集。

从第18行到第21行的程序语句,是使用“-”运算符和调用difference方法来求两个集合的差集,即返回在第一个集合中有且在第二个集合中没有的元素。

在前文中介绍过,可以用元组来保证列表元素的不可操作性,在上面范例程序的第23行中通过调用frozenset来保证集合元素的不可操作性。如果去掉第24行到第26行的注释,就会发现无法通过程序代码来修改frozenset类型的unChangedSet中的元素,由此可以验证这种方式实现的列表的元素的“不可操作性”。

2.2.3 通过覆盖sort定义排序逻辑

在集合(以及之前的列表)中,都可以通过调用sort方法对集合内的元素进行排序。在默认的情况下,sort方法是会按升序的方式排序集合中的元素,这里就涉及一个问题,程序员在开发时如何定义排序的标准?比如如何把排序的标准设置为“降序”?

在下面的SetSortDemo.py范例程序中,演示了列表降序排列的方法,具体做法是,在调用sort方法时,传入了“定义排序规则”的desc方法。

1    # !/usr/bin/env python
2    # coding=utf-8
3    # 定义降序规则
4    def desc(x, y):
5        if x < y:
6            return 1         # 如果x小于y,则x排在y之前
7        elif x > y:
8            return -1     # 如果x大于y,则x排在y之后
9        else:
10            return 0         # 否则并列
11    # 定义待排序的numbers列表
12    numbers=[5, 58, 47 ,75 ,100]
13    numbers.sort(desc)     # 在排序时用到desc方法
14    print numbers           # 输出[100, 75, 58, 47, 5]
15    numbers.sort()
16    print numbers           # 输出[5, 47, 58, 75, 100]

在第13行中通过调用sort方法对numbers列表进行排序,与之前不同的是,这里传入了desc方法,用来定义排序的规则。

第4行到第10行的程序语句定义desc方法时,定义的排序规则是:如果x小于y,则返回1,即x排在y之前;如果大于,则返回-1,x排在y之后;如果相等则返回0,即两数并列。在第14行和第16行中,打印了以不同方式排序后的列表,从输出结果上来看,分别实现了降序和升序的排序。

其实,这里定义排序规则和在sort方法里通过参数传入规则的代码都不复杂,但请大家熟悉这种“通过传入参数定义规则”的编写程序的方式,这种定义排序规则的做法在实际项目中会经常用到。