A.txt包含看起来像这样的行(或者是它的一小部分):
Green- Blue- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 1
Green- Blue- 1
基本上,最后一个字符串是1或3.假设上面的样本持续了很长时间,我需要做的是找到最大数量的连续行,最后有1个,同时保持3s的数量小于或等于某个数字(比方说2)。例如,假设A.txt完整地看起来像这样:
Green- Blue- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 3
Green- Blue- 1
Green- Purple- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 1
Blue- Blue- 3
然后脚本会将以下行写入另一个文本文件:
Green- Blue- 1
Green- Purple- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 1
我将如何编码?提前谢谢!
答案 0 :(得分:3)
你真的别无选择地遍历整个文件,跟踪最大的序列。这是我的看法,用一个函数封装:它使用一个堆栈并逐行遍历文件,因此它对于大型输入文件应该是内存效率。
def foo(in_file, out_file, max_count):
biggest, stack = [], []
count = 0
with open(in_file) as f:
for line in f:
if line[-2] == '3':
count += 1
if count > max_count:
if len(stack) > len(biggest):
biggest = list(stack)
# this line trims the list after the first element that ends with '3'
stack = stack[stack.index(next(x for x in stack if x[-2] == '3')) + 1:]
count = max_count
stack.append(line)
with open(out_file, 'w') as f:
f.write(''.join(max(biggest, stack)))
注意:仅当文件末尾包含空行时,这将按预期工作,并假定max_count
始终大于0(否则调用{{ 1}}抛出一个未处理的异常。)
答案 1 :(得分:1)
首先,起始字符串完全不相关。其次,可能有100种方法可以解决这个问题。我只想列出我认为最好的那个
我们还可以假设起始边界始终为:
a)清单的开头
b)在3
之后我们还可以假设结束边界始终为:
a)清单的结尾
b)就在3
之前所以,让我们做一个新的
threes = [-1, ... numbers.length + 1]
其中...是每个3的行号。我将-1和numbers.length + 1添加到列表中以“假装”我们的列表被两个3包围,以简化逻辑
由于未在问题陈述中指定,我们还可以假设列表将始终包含至少2个3,如果可能的话。原因是,这将给我们带来最大的范围。
现在,我们需要做的就是找到任意两个三分之一的最大行号范围。
max_range = -1 # number of lines between two 3s.
max_start = -1 # start line
max_end = -1 # end line
if len(threes) == 2: # special case here. If the original list contains no 3s, we will take the whole list.
max_start = threes[0]
max_end = threes[1]
max_range = max_end - max_start
else:
for i in range(len(threes) - 2):
# The general case. Find the range between any two consecutive 3s.
start = threes[i]
end = threes[i + 2]
range = end - start
if range > max_range:
max_start = start
max_end = end
max_range = range
max_start += 1
max_end -= 1
max_range -= 2
这里有一些边缘情况需要解决,但这应该可以让你开始。
第一个边缘情况(在问题中没有真正定义)如果我最终得到[1,1,1,3,3]会发生什么?我应该拿0-3,0-4还是0-5?一切似乎都是有效的解决方案。在这段代码中,我取0-5因为没有指定,它使代码更简单。
答案 2 :(得分:1)
您可以查看使用itertools.groupby
的组合存储索引的内容txt = '''Green- Blue- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 3
Green- Blue- 1
Green- Purple- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 1
Blue- Blue- 3'''
import operator
from itertools import groupby
str_lst = list( enumerate( txt.split('\n') ) )
grp_lst = [ list(g) for k, g in groupby( [ (k,v[-1]) for k, v in str_lst ], key=operator.itemgetter(1) ) ]
filter_lst = [ (i[0], len(i)) for i in grp_list if i[0][1] == '1' ]
for i in grp_list:
if i[0] == max( dict(filter_lst).items(), key=operator.itemgetter(1) )[0]:
idx = grp_list.index(i)
break
for i in sum( grp_lst[idx:idx+3], [] ):
print (str_lst[i[0]][1])
输出:
Green- Blue- 1
Green- Purple- 1
Red- Black- 3
Brown- Blue- 3
Black- Red- 1
答案 3 :(得分:1)
这是我的解决方案。
首先,读取文件并仅提取您实际需要的数据,即最后一位数字。
x = ''
for i, line in enumerate(txt.split('\n')):
try:
x += line[-1]
except IndexError:
pass
你最终得到一个包含所有1和3的字符串,因为它们一行一行地出现。
>>>print x
'1333113313'
此时,您可以迭代此字符串并收集所有可能不包含3次超过两次的子字符串。您可以跟踪字符串第一个字母的索引及其长度。
results = {}
for i, n in enumerate(x):
for idx in range(i+1, len(x)):
if x[i:idx].count('3') <= 2:
results[i] = len(x[i:idx])
else:
break
最后,根据长度对结果进行排序,最后得到最长序列开始的行号以及它持续的行数。
m = sorted(results.items(), key=operator.itemgetter(1))[-1]
>>>print m
(4, 5)
您可以使用此信息来编写输出文件。因此,您将从第4行开始保存5行。
with open('myfile.txt', 'r') as inp, open('out.txt', 'w') as out:
for line in inp.readlines()[m[0]:m[0]+m[1]]
out.write(line)