分类: python/ruby
2012-09-23 13:35:06
code kata为提高编程能力的一系列练习,是关于数据抽取的,其给出了两个编程题目,要求分别实现,然后把共同部分抽象出来,重新实现这两个程序。
题目一: weather.dat为某个地方6月的温度数据,要求输出温差最大的天,dy为day,mxt为该日最大温度,mnt为该日最小温度。
weather.dat
题目二:football.dat为某个联赛各个队伍的比赛成绩,要求输出第二列与第三列差异最大的队伍。
football.dat
href="">sunsite.tut.fi/rec/riku/soccer_data/tab/93_94/table.eng0.01_02.html
|
问题一的思路:
1. 遍历文件,如果该行的第一个单词为天数(数字),那么取得天数、最大温度、最小温度并放到返回列表中;
2. 返回列表排序,最大温度-最小温度最大的元素放在最前面;
3. 取得列表头的第一个元素;
问题二的思路:
1. 遍历该文件,如果该行的第一个单词为数字 点,那么取得队伍、p分数、w分数,并放入到返回列表中;
2. 对返回列表进行排序,p分数-w分数绝对值最大的放在最前面;
3. 取得列表头的第一个元素。
显然,两者的共同点在于整体处理流程的相似,而在每个流程中处理细节又能不同,如两者都需要遍历文件,抽取所需数据列,并排序得到最终结果,而它们的排序方法是不同的。
最终得到的通用部分如下:
-module(file_common). -export([process/4, process_stream/4, is_int_string/1]). process(filename, sortpred, isdataline, lineparser) -> {ok, stream} = file:open(filename, read), line = io:get_line(stream, ''), resultlist = process_stream(stream, line, isdataline, lineparser), hd(lists:sort(sortpred, resultlist)). process_stream(_stream, eof, _isdataline, _lineparser)-> []; process_stream(stream, line, isdataline, lineparser) -> nextline = io:get_line(stream, ''), case isdataline(line) of false -> process_stream(stream, nextline, isdataline, lineparser); true -> result = lineparser(line), [result | process_stream(stream, nextline, isdataline, lineparser)] end. is_int_string(str) -> try list_to_integer(str) of _int -> true catch error:_ -> false end. |
这里非常有趣的是,抽取得到的通用部分分成两种情况,一是整个处理流程,如上面的process,二是一些通用的辅助小函数,如上面的is_int_string,其用来判断某个字符串是否为数字字符串。对于第二种抽象,是非常容易的,这里就不详细说明了。
对于整体处理流程的抽象,必须先定义出解决该问题的通用结构,并通过回调函数如sortpred,isdataline,lineparser来实现不通用部分。这意味着,必须先定义出问题的通用处理流程,每个步骤的输入、输出。
在这里,通用处理流程抽象如下:
1. 遍历文件,生成结果列表; 1.1 遍历文件的每一行; 1.2 如果该行是数据行,那么解析该行得到结果tuple,并加入到返回列表中,处理下一行; 1.3 如果改行不是数据行,那么接着处理; 2. 对结果列表进行排序; 2.1 使用排序谓词对列表进行排序; 3. 返回排序后列表的第一个元素; |
在没有对通用部分进行抽象的时候,并没有判断该行是否为数据行的概念,而是把其当做行解析的一部分,在对通用部分进行抽象过后,得到:把判断该行是否未数据行当做单独的函数,而不是耦合在解析函数内。从这个角度上来说,把程序泛化能够改进程序的结构。下面为处理weather.dat第一版的程序和第二版即抽取通用部分后的程序,如下
第一版:解析行的函数包括了判断该行是否为数据行 processline(line) -> |
第二版:由于需要通用公共部分,发现判断该行是否是数据行是个通用的功能,不仅仅在题目一中需要用到,在题目二中也需要用到,因此把其抽象出来。 isdataline = fun(line) -> |
本文章的几个程序放在。