ch5-处理数据,抽取-整理-推导

场景:教练kelly有4个选手James\Sarah\Julie\Mikey,他们每跑600米,教练就会计时并把时间记录在计算机的一个文件中,总共4个文件:James.txt\Sarah.txt\Julie.txt\Mikey.txt,分别记录4个选手的时间数据。

期望:教练需要一种快捷的方法能够很快了解到每个选手跑的最快的3个时间

 

1、将文件中选手数据读入到各自的列表中,并屏幕显示这些列表;

data.strip().split(','):此为“方法串链”,从左到右读这种方法链。

2、对数据进行排序

原地排序:指按照指定的顺序排列数据,然后用排序后的数据替换原来的数据,原来的顺序会丢失。升序为sort() BIF,降序需增加参数reverse=Ture.

复制排序:指按照指定的顺序排列数据,然后返回原数据的一个有序副本,原数据的顺序依然保留,只是对一个副本排序。升序为sorted() BIF,降序需增加参数reverse=Ture.

>>> data=[6,3,1,2,4,5]
>>> data
[6, 3, 1, 2, 4, 5]
>>> data.sort()  #原地排序
>>> data
[1, 2, 3, 4, 5, 6]
>>> #原地排序结果显示原数据的顺序已经改变
>>> 
>>> data=[6,3,1,2,4,5]
>>> data
[6, 3, 1, 2, 4, 5]
>>> data2=sorted(data)  #复制排序
>>> data2
[1, 2, 3, 4, 5, 6]
>>> data
[6, 3, 1, 2, 4, 5]
>>> #复制排序结果显示原数据的顺序并未改变
>>> 
>>> data=[6,3,1,2,4,5]
>>> data
[6, 3, 1, 2, 4, 5]
>>> data.sorted()
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    data.sorted()
AttributeError: 'list' object has no attribute 'sorted'
>>> 
>>> data=[6,3,1,2,4,5]
>>> data
[6, 3, 1, 2, 4, 5]
>>> data.sort(reverse=True) #原地排序降序
>>> data
[6, 5, 4, 3, 2, 1]
>>>
>>> data=[6,3,1,2,4,5]
>>> data
[6, 3, 1, 2, 4, 5]
>>> data2=sorted(data,reverse=True)#复制排序降序
>>> data2
[6, 5, 4, 3, 2, 1]
>>>

使用复制排序对教练的4个选手数据进行排序:

函数串链:允许对数据应用一系列函数,与方法串链不同,函数串链要从右向左读

排序结果显示:2-55居然在2.18之前,数据格式不统一,分钟和秒的分隔符导致排序混乱。

Python可以对字符串排序,升序排序时短横线-点号-冒号;

需要修正数据!!

3、数据修正

定义一个函数sanitize(),从各个选手的列表接收一个字符串作为输入,然后处理这个字符串,将从中找到的短横线或者冒号替换为一个点号,并返回清理过的字符串。
如果字符串已经包含一个点号,则无需再替换;

将现有的数据转换为经过清理的版本。

def sanitize(time_string):
    if '-' in time_string:
        splitter = '-'
    elif ':' in time_string:
        splitter = ':'
    else:
        return(time_string)
    (mins, secs) = time_string.split(splitter)
    return(mins + '.' + secs)
    
with open('james.txt') as jaf:
    data = jaf.readline()
james = data.strip().split(',')

with open('julie.txt') as juf:
    data = juf.readline()
julie = data.strip().split(',')

with open('mikey.txt') as mif:
    data = mif.readline()
mikey = data.strip().split(',')

with open('sarah.txt') as saf:
    data = saf.readline()
sarah = data.strip().split(',')

clean_james = []
clean_julie = []
clean_mikey = []
clean_sarah = []

for each_t in james:
    clean_james.append(sanitize(each_t))
    
for each_t in julie:
    clean_julie.append(sanitize(each_t))
    
for each_t in mikey:
    clean_mikey.append(sanitize(each_t))
    
for each_t in sarah:
    clean_sarah.append(sanitize(each_t))

print(sorted(clean_james))
print(sorted(clean_julie))
print(sorted(clean_mikey))
print(sorted(clean_sarah))

清理成功!!格式不但一致,而且数据有序!!

但是代码重复,代码创建了4个列表保存从文件中读入的数据,又创建4个列表保存清理过的数据,到处都在迭代。。。。。

还有更好的处理办法---转换列表,python提供了一个很好用的工具(推导列表)来完成转换,涉及推导列表是为了减少将一个列表转换为另一个列表时所需编写的代码。

4、推导列表

列表转换需要做4件事:

  1)创建一个新列表存放转换后的数据;

  2)迭代处理原列表中的各项数据;

  3)每次迭代时完成转换

  4)将转换后的数据追加到新列表;

clean_james = []  #1.创建

for each_t in james:   #2.迭代
    clean_james.append(sanitize(each_t))  #3.转换    4.追加
clean_james=[sanitize(each_t) for each_t in james]   #列表推导,一行代码完成创建、迭代、转换、追加

列表推导来处理教练的4个计时值列表:

正如我们期望的,输出与前面完全一致。

注意:你可能想在列表推导中使用函数链sorted(sanitize(t)),但是千万别这样做!!因为sanitize(t)是输出一个数据项,sorted() BIF希望对一个列表排序,而不是对单个的数据项。

5、迭代删除重复项

任务:生成每个选手的3次最快时间

使用标记法指定单个的列表项:james[0]、james[1]、james[2]

列表分片:james[0:3]

使用迭代删除重复项,并获得每个选手的3次最快时间。

def sanitize(time_string):
    if '-' in time_string:
        splitter = '-'
    elif ':' in time_string:
        splitter = ':'
    else:
        return(time_string)
    (mins, secs) = time_string.split(splitter)
    return(mins + '.' + secs)

with open('james.txt') as jaf:
    data = jaf.readline()
james = data.strip().split(',')

with open('julie.txt') as juf:
    data = juf.readline()
julie = data.strip().split(',')

with open('mikey.txt') as mif:
    data = mif.readline()
mikey = data.strip().split(',')

with open('sarah.txt') as saf:
    data = saf.readline()
sarah = data.strip().split(',')

#将排序的数据替换原来无序且不一致的数据
james = sorted([sanitize(t) for t in james])  
julie = sorted([sanitize(t) for t in julie])
mikey = sorted([sanitize(t) for t in mikey])
sarah = sorted([sanitize(t) for t in sarah])

unique_james = []  #创建一个新列表,存储唯一的数据
for each_t in james:     #在现有数据基础上迭代处理
    if each_t not in unique_james:   #若这个数据不在新列表中
        unique_james.append(each_t)   #将这个唯一的数据追加到新列表中
print(unique_james[0:3])       #从列表分片中得到前3个数据项,并打印到屏幕上

unique_julie = []
for each_t in julie:
    if each_t not in unique_julie:
        unique_julie.append(each_t)
print(unique_julie[0:3])

unique_mikey = []
for each_t in mikey:
    if each_t not in unique_mikey:
        unique_mikey.append(each_t)
print(unique_mikey[0:3])

unique_sarah = []
for each_t in sarah:
    if each_t not in unique_sarah:
        unique_sarah.append(each_t)
print(unique_sarah[0:3])
>>> 
===== RESTART: D:\workspace\headfirstpython\chapter5\page162\page162.py =====
['2.01', '2.22', '2.34']
['2.11', '2.23', '2.59']
['2.22', '2.38', '2.49']
['2.18', '2.25', '2.39']
>>> 

成功了!!

但是从列表中删除重复项的代码本身是重复的。可以将重复的代码抽取到一个小函数中。

6、快速用集合删除重复项

  1)用集合删除重复项

python集合最突出的特性:集合中的数据项是无序的,而且不允许重复。如果试图向集合中添加已存在的数据,Python就会忽略它。

distances=set()  #创建一个新的空集合,并赋至一个变量
distances={10.6,11,8,10.6,'two',7}  #提供的数据值列表中的重复项10.6将会被忽略
distances=set(james)   #james中的所有重复项都被忽略

工厂函数:用于创建某种类型的新的数据项。例如set()就是一个工厂函数。在真实的世界中,工厂会生产产品,这个概念因此而得名。

代码优化:

太棒啦!!!

posted @ 2016-04-21 17:32  垄上行  阅读(356)  评论(0编辑  收藏  举报