我浏览了“Python中的文本处理”并尝试了example关于Schwartzian排序。
我使用以下结构来获取也包含空行的样本数据。我按第五栏对这些数据进行了排序:
383230 -49 -78 1 100034 '06 text'9562'text'720'text'8667
335067 -152 -18 3 100030 'text'2400'text'2322'text'696
136592 21 230 3 100035 '03。 text'10368'text'1838'text'977
用于Schwartzian排序的代码:
for n in range(len(lines)): # Create the transform
lst = string.split(lines[n])
if len(lst) >= 4: # Tuple w/ sort info first
lines[n] = (lst[4], lines[n])
else: # Short lines to end
lines[n] = (['\377'], lines[n])
lines.sort() # Native sort
for n in range(len(lines)): # Restore original lines
lines[n] = lines[n][1]
open('tmp.schwartzian','w').writelines(lines)
我不知道作者是如何使用此代码将短行或空行放到文件末尾的。行在if-else结构之后排序,从而将空行提升到文件顶部。当然,短行当像在示例中实现的自定义排序(fourth_word函数)一样工作。
这现在困扰着我,所以任何想法?如果我对此是正确的,那么你如何确保短线实际上保留在文件末尾?
编辑:我注意到'\ 377'周围的方括号。这搞砸了sort()所以我删除了那些括号并输出开始工作。
else: # Short lines to end
lines[n] = (['\377'], lines[n])
print type(lines[n][0])
>>> (type 'list')
我接受了nosklo的回答,以便对'\ 377'的含义及其改进的算法进行详细说明。非常感谢其他答案!
如果好奇的话,我使用2 MB样本文件,使用自定义排序花费0.95秒,使用Schwartzian排序花费0.09,同时创建相同的输出文件。它有效!
答案 0 :(得分:2)
与问题没有直接关系,但请注意在python的最新版本中(我认为是2.3或2.4),可以使用key
参数自动执行转换和非转换,或sort()
或sorted()
。例如:
def key_func(line):
lst = string.split(line)
if len(lst) >= 4:
return lst[4]
else:
return '\377'
lines.sort(key=key_func)
答案 1 :(得分:1)
我不知道这是什么问题,所以我会尝试以一般方式澄清事情。
此算法通过获取第4个字段并将其放在行的前面来对行进行排序。然后内置的sort()
将使用此字段进行排序。稍后原始线路将恢复。
空行或短于5个字段的行落入此结构的else
部分:
if len(lst) >= 4: # Tuple w/ sort info first
lines[n] = (lst[4], lines[n])
else: # Short lines to end
lines[n] = (['\377'], lines[n])
它会在列表的第一个字段中添加['\377']
进行排序。该算法希望'\ 377'(ascii表中的最后一个字符)将更大比在第5个字段中找到的任何字符串。因此,在进行排序时,原始行应该排在最后。
我希望澄清这个问题。如果没有,也许你应该指出exaclty你想知道什么。
同一算法的更好的通用版本:
sort_by_field(list_of_str, field_number, separator=' ', defaultvalue='\xFF')
# decorates each value:
for i, line in enumerate(list_of_str)):
fields = line.split(separator)
try:
# places original line as second item:
list_of_str[i] = (fields[field_number], line)
except IndexError:
list_of_str[i] = (defaultvalue, line)
list_of_str.sort() # sorts list, in place
# undecorates values:
for i, group in enumerate(list_of_str))
list_of_str[i] = group[1] # the second item is original line
您提供的算法与此算法相同。
答案 2 :(得分:0)
空行不会通过测试
if len(lst) >= 4:
所以它会将['\ _ 377']作为其排序键,而不是数据的第5列,即lst[4]
(lst[0]
是第一列)。
答案 3 :(得分:0)
好吧,它会在最后对几乎的短行进行排序,但并不总是如此。
实际上,“幼稚”和施瓦兹版都有缺陷(以不同的方式)。 Nosklo和wbg已经解释了算法,如果你试图在schwartzian版本中找到错误,你可能会学到更多,因此我现在只给你一个提示:
包含特定文字的长行 在第四列中将稍后排序 而不是短线。
如果您需要更多帮助,请添加评论。
答案 4 :(得分:0)
尽管Schwartzian变换的使用已经过时了,但值得一提的是,你可以用这种方式编写代码,以避免以\377
开头的行[4]的行被分类到错误的地方
for n in range(len(lines)):
lst = lines[n].split()
if len(lst)>4:
lines[n] = ((0, lst[4]), lines[n])
else:
lines[n] = ((1,), lines[n])
由于元组比较元组,因此以1
开头的元组将always
排序到底部。
另请注意,测试应为len(list)>4
而非>=
当使用现代等价的AKA key=
函数
def key_func(line):
lst = line.split()
if len(lst)>4:
return 0, lst[4]
else:
return 1,
lines.sort(key=key_func)