由于种种原因,获取的数据中可能会存在重复的数据,在进行后续的操作之前,必须进行去重处理。字典中各键值对的键必须唯一,利用这个性质可以对数据进行去重。除了使用字典进行处理,还介绍列表数据的去重。另外,集合中的元素要求是唯一的,利用这一点也可以进行去重处理。[大谦Excel,dqexcel点com]
使用列表去重
对列表进行去重,需要另外创建一个列表。对原始列表进行遍历,如果原始列表中的元素在新列表中不存在,则添加到新列表中,否则不添加。例如:
>>> a=[1,2,3,4,3,1] #有重复值的列表
>>> b=[1] #新列表
>>> for i in range(len(a)): #遍历原始列表
r=a[i] #原始列表中的当前值r
if r not in b: #如果r在新列表中不存在
b.append(r) #r添加到新列表
>>> b
[1, 2, 3, 4]
所以,最后新列表中重复的值被去除了。
按照这个思路,对图6-3中工作表的数据进行去重处理。
1 import xlwings as xw
2 import os
3 root = os.getcwd()
4 app = xw.App(visible=True, add_book=False)
5 wb=app.books.open(root+r"/身份证号-去重.xlsx",read_only=False)
6 sht=wb.sheets(1)
7 rng=sht.range("A1", sht.cells(sht.cells(1,"B").end("down").row, "E"))
8 lst=[rng.rows(1).value] #创建列表
9 for i in range(rng.rows.count):
10 r=rng.rows(i).value
11 if r not in lst: #如果行数据在列表中不存在,添加到列表
12 lst.append(r)
13 sht.range("G1").value=lst
第1-5行的说明同6.1.1小节的代码说明。
第6-7行获取第1个工作表,用range属性获取数据所在的单元格区域对象。
第8行创建列表lst,并用第1行数据进行初始化。
第9-12行用一个for循环往新列表lst中添加不重复的行数据。第11行判断当前行在新列表中是否存在,如果不存在就添加到新列表,否则不添加。
第13行使用了xlwings包的选项功能将列表输出到左上角单元格坐标为G1的区域。options属性的expand参数的值设置为"table",表示按二维表的方式将新列表的数据写入到工作表。关于xlwings包的选项功能,第4章有更详细的介绍,请参阅。
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,去重后的数据如图6-3中处理后工作表中右侧数据所示。
图6-3 使用列表去重
使用集合去重
集合中的元素是不重复的,利用这个特点,可以对序列数据去重。下面先创建一个列表,列表中的元素有2个是重复的。使用set函数将该列表转换为集合,得到的集合会自动去重。
>>> a=[1,4,3,2,3,1]
>>> b=set(a)
>>> b
{1, 2, 3, 4}
按照这个思路,对图6-3中工作表的数据进行去重处理。
代码根据工号数据,首先用set函数进行去重并得到一个只包含唯一工号的列表,创建一个新的列表,然后用for循环遍历工作表中的每一行,如果该行的工号数据在工号列表中,把该行添加到新列表中,工号列表中删除对应工号,继续这个过程。最后每个工号对应有唯一行数据添加到新列表中,即为去重后的数据。
1 import xlwings as xw
2 import os
3 root = os.getcwd()
4 app = xw.App(visible=True, add_book=False)
5 wb=app.books.open(root+r"/身份证号-去重.xlsx",read_only=False)
6 sht=wb.sheets(1)
7 ind=sht.range("A1", sht.cells(sht.cells(1,"A").end("down").row, "A")).value
8 inds=set(ind) #工号列表转集合,去重
9 indl=list(inds) #去重后集合转列表indl
10 rng=sht.range("A1", sht.cells(sht.cells(1,"B").end("down").row, "E"))
11 dd=[] #创建列表dd,保存去重后的行数据
12 for i in range(rng.rows.count): #遍历每行数据
13 if sht[i,0].value in indl: #如果该行工号在indl中
14 indl.remove(sht[i,0].value) #从列表中删除它
15 dd.append(rng.rows(i+1).value) #添加行数据到dd
16 sht.range("G1").options(expand="table").value=dd #dd写入工作表
第1-5行的说明同6.1.1小节的代码说明。
第6-7行获取第1个工作表,用range函数获取第1列的工号数据并以列表形式返回。
第8-9行将返回的列表用set函数转换为集合,工号去重,然后用list函数将集合转换成列表。
第10行用range属性获取数据所在的单元格区域对象。
第11行创建新的空列表dd。
第12-15行用一个for循环往新列表dd中添加不重复的行数据。第13行判断当前行的工号在新列表中是否存在,如果存在就在新列表中删除该工号,把当前行的数据添加到dd列表。在新列表中删除该工号,可以保证该工号对应的行数据在dd列表中只被添加一次。
第16行使用了xlwings包的选项功能将列表输出到左上角单元格坐标为G1的区域。options属性的expand参数的值设置为"table",表示按二维表的方式将新列表的数据写入到工作表。关于xlwings包的选项功能,第4章有更详细的介绍,请参阅。
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,去重后的数据如图6-3中处理后工作表中右侧数据所示。
使用字典去重
6.1.1小节讲到了,用新的键对字典索引赋值,可以给字典添加新元素。对图6-3中工作表的数据进行去重处理。创建字典,字典中的键值对,键由第1列的工号组成,值由它对应的行数据组成。使用字典对象的keys方法可以获取当前所有的键。添加键值对时如果键已经存在,则不添加,否则添加。这样,最后得到的所有键值对的值就是去重后的数据。
1 import xlwings as xw
2 import os
3 root = os.getcwd()
4 app = xw.App(visible=True, add_book=False)
5 wb=app.books.open(root+r"/身份证号-去重.xlsx",read_only=False)
6 sht=wb.sheets(1)
7 rng=sht.range("A1", sht.cells(sht.cells(1,"B").end("down").row, "E"))
8 dd={} #创建字典dd
9 for i in range(rng.rows.count): #遍历行数据
10 if sht[i,0].value not in dd.keys(): #如果dd的键中不包括该行工号
11 dd[sht[i,0].value]=rng.rows(i+1).value #添加行数据到字典的值
12 lst=list(dd.values()) #字典的值转成列表
13 sht.range("G1").value=lst #列表数据写入工作表
第1-5行的说明同6.1.1小节的代码说明。
第6-7行获取第1个工作表,用range函数获取第1列的工号数据并以列表形式返回。
第8行创建空字典dd。
第9-11用一个for循环往新列表dd中添加不重复的行数据。第10行判断当前行的工号在keys方法返回的所有键组成的列表中是否存在,如果不存在就把当前行的数据添加到dd列表。因为键已存在的就不添加,所以起到去重的作用。
第12行用dd字典对象的values方法获取所有值,用list函数转换为列表lst。
第13行使用了xlwings包的选项功能将列表输出到左上角单元格坐标为G1的区域。options属性的expand参数的值设置为"table",表示按二维表的方式将新列表的数据写入到工作表。关于xlwings包的选项功能,第4章有更详细的介绍,请参阅。
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,去重后的数据如图6-3中处理后工作表中右侧数据所示。
使用字典对象的fromkeys方法去重
使用字典对象的fromkeys方法可以利用给定序列生成字典,给定序列的值去重后作为字典的键,字典所有的值都为None。下面创建一个列表和一个空的字典,然后用字典对象的fromkeys方法用列表数据创建字典。
>>> a=[1,4,3,2,3,1]
>>> b={}
>>> dic=b.fromkeys(a)
>>> dic
{1: None, 4: None, 3: None, 2: None}
可见,fromkeys方法创建字典时对列表数据进行了去重。使用字典对象的keys方法获取所有键,用list方法转换为列表。
>>> lst=list(dic.keys())
>>> lst
[1, 4, 3, 2]
这样就间接得到了对原始列表a进行去重后的结果。
按照这个思路,对图6-3中工作表的数据进行去重处理。
1 import xlwings as xw
2 import os
3 root = os.getcwd()
4 app = xw.App(visible=True, add_book=False)
5 wb=app.books.open(root+r"/身份证号-去重.xlsx",read_only=False)
6 sht=wb.sheets(1)
7 ind=sht.range("A1", sht.cells(sht.cells(1,"A").end("down").row, "A")).value
8 d={} #创建字典
9 inds=d.fromkeys(ind) #用工号作键生成字典inds
10 indl=list(inds.keys()) #字典inds的键转成列表indl
11 rng=sht.range("A1", sht.cells(sht.cells(1,"B").end("down").row, "E"))
12 dd=[] #创建列表dd
13 for i in range(rng.rows.count): #遍历行数据
14 if sht[i,0].value in indl: #如果行工号在列表indl中
15 indl.remove(sht[i,0].value) #从indl中删除行工号
16 dd.append(rng.rows(i+1).value) #添加行数据到dd
17 sht.range("G1").options(expand="table").value=dd #将dd数据写入工作表
第1-5行的说明同6.1.1小节的代码说明。
第6-7行获取第1个工作表,用range函数获取第1列的工号数据并以列表形式返回。
第8行创建一个空字典d。
第9-10行用fromkeys方法对工号去重后生成字典,然后用list函数将字典的全部键转换成列表。
第11行用range属性获取数据所在的单元格区域对象。
第12行创建新的空列表dd。
第13-16行用一个for循环往新列表dd中添加不重复的行数据。第13行判断当前行的工号在新列表中是否存在,如果存在就在新列表中删除该工号,把当前行的数据添加到dd列表。在新列表中删除该工号,可以保证该工号对应的行数据在dd列表中只被添加一次。
第17行使用了xlwings包的选项功能将列表输出到左上角单元格坐标为G1的区域。options属性的expand参数的值设置为"table",表示按二维表的方式将新列表的数据写入到工作表。关于xlwings包的选项功能,第4章有更详细的介绍,请参阅。
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,去重后的数据如图6-3中处理后工作表中右侧数据所示。
多表去重
对于分布在多个工作表中的同格式数据进行去重,思路是首先将多个工作表合并到一张工作表,然后使用单表去重的方法进行去重。
图6-4中某单位的工作人员信息分散在不同部门,进行多表去重。
1 import xlwings as xw
2 import os
3 root = os.getcwd()
4 app = xw.App(visible=True, add_book=False)
5 wb=app.books.open(root+r"/身份证号-多表去重.xlsx",read_only=False)
6 #合并到汇总工作表
7 sht2=wb.api.Sheets("汇总")
8 for sht in wb.api.Sheets: #遍历各工作表
9 if sht.Name not in ["汇总","去重"]: #不包括这两个表
10 hrow=sht2.UsedRange.Rows.Count #粘贴位置
11 sht.UsedRange.Copy(sht2.Cells(hrow,1)) #复制数据到汇总表
12 #单表去重,结果显示在去重工作表
13 sht2=wb.sheets("汇总")
14 rng=sht2.range("A1",sht2.cells(sht2.cells(1,"A").\
end("down").row,sht2.cells(1,"A").end("right").column))
15 dd={}
16 for i in range(rng.rows.count): #遍历汇总表每行数据
17 if sht2[i,0].value not in dd.keys(): #如果dd的键中不包括该行工号
18 dd[sht2[i,0].value]=rng.rows(i+1).value #添加行数据到字典的值
19 lst=list(dd.values()) #字典的值转成列表
20 sht3=wb.sheets("去重")
21 sht3.range("A1").options(expand="table").value=lst #数据写入去重工作表
第1-5行的说明同6.1.1小节的代码说明。
第7-11行将财务部、生产部和销售部的人员数据合并到汇总工作表。这里使用了API方法,用区域对象的Copy方法将各部门数据逐个复制到汇总表。hrow计算当前汇总表中数据的行数,以便确定汇总表中下一次粘贴的位置。
第13-21行采用字典法对汇总表中的数据进行去重,并将去重后的数据写入去重工作表中。关于字典法去重,请参见6.2.3小节内容。
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,去重后的数据如图6-4中处理后工作表中所示。
图6-4 多表去重
跨表去重-使用字典和集合
这里讲的跨表去重,是从一个工作表中剔除另一个工作表中包含的数据。6.2.2小节介绍了使用集合去重,使用集合,不仅可以对单个列表内部的数据进行去重,还可以通过差集运算对两个工作表进行跨表去重。
下面创建两个列表a和b,用set函数将它们去重并转换为集合c和d,求它们的差集e=c-d,最后用list函数将它转换为列表,该列表即为从列表a中剔除列表b包含的数据后的新列表。
>>> a=[1,2,3,4,5,6,4,2,1]
>>> b=[3,5,1,5]
>>> c=set(a) #列表a转成集合,去重
>>> c
{1, 2, 3, 4, 5, 6}
>>> d=set(b) #列表b转成集合,去重
>>> d
{1, 3, 5}
>>> e=c-d #求两个集合的差集
>>> e
{2, 4, 6}
>>> lst=list(e) #差集转列表
>>> lst
[2, 4, 6]
按照这个思路,对图6-5中上面两个工作表给定的数据进行跨表去重,去重后的结果写入到第3个工作表中。
1 import xlwings as xw
2 import os
3 root = os.getcwd()
4 app = xw.App(visible=True, add_book=False)
5 wb=app.books.open(root+r"/身份证号-跨表去重.xlsx",read_only=False)
6 sht=wb.sheets(1)
7 ind=sht.range("A2", sht.cells(sht.cells(1,"A").end("down").row, "A")).value
8 inds1=set(ind) #工作表1工号去重
9 sht2=wb.sheets(2)
10 ind2=sht2.range("A2", sht2.cells(sht2.cells(1,"A").end("down").row, "A")).value
11 inds2=set(ind2) #工作表2工号去重
12 inds=inds1-inds2 #求工号差集
13 indl=list(inds) #工号差集转列表indl
14 rng=sht.range("A2", sht.cells(sht.cells(1,"B").end("down").row, "E"))
15 dd=[] #创建列表dd
16 for i in range(rng.rows.count): #遍历行数据
17 if sht[i+1,0].value in indl: #如果工作表1中行工号在indl中
18 indl.remove(sht[i+1,0].value) #indl中删除该工号
19 dd.append(rng.rows(i+1).value) #dd列表中添加该行数据
20 sht3=wb.sheets(3)
21 sht3.range("A2").options(expand="table").value=dd #dd数据写入工作表3
第1-5行的说明同6.1.1小节的代码说明。
第6-8行将第1个工作表中第1列的工号数据用set函数去重并转换为集合inds1。
第9-11行将第2个工作表中第1列的工号数据用set函数去重并转换为集合inds2。
第12-13行对inds1和inds2进行求差集的运算,得到跨表去重后的工号。用list函数将差集转换为列表indl。
第14行用工作表对象的range方法获取第1个工作表数据所在的区域对象。
第15行创建空的列表dd。
第16-19行用一个for循环往新列表dd中添加不重复的行数据。第17行判断当前行的工号在列表indl中是否存在,如果存在就在列表indl中删除该工号,把当前行的数据添加到dd列表。在列表indl中删除该工号,可以保证该工号对应的行数据在dd列表中只被添加一次。
第20-21行使用了xlwings包的选项功能将dd列表输出到第3个工作表中左上角单元格坐标为A2的区域。options属性的expand参数的值设置为"table",表示按二维表的方式将新列表的数据写入到工作表。关于xlwings包的选项功能,第4章有更详细的介绍,请参阅。
在Python IDLE文件脚本窗口,在"Run"菜单中单击"Run Module"选项,去重后的数据如图6-5中处理后工作表3中所示。
图6-5 跨表去重