Нахождение метки, предшествующей самой длинной строке в файле - PullRequest
0 голосов
/ 21 октября 2011

У меня есть файл в формате

_line 1
this is a string on a line
_line 2
this is another string
_line 3
short line

Я пытаюсь написать код на Python, чтобы получить метку _line X для строки под ней, которая имеет самую длинную длину строки. Можете ли вы помочь мне исправить мой код, пожалуйста? Вот что у меня есть.

f = open('test.txt', 'r')
print f

read="null"
top_read_line_length="0"
topreadline="null"
for line in f:
    checkifread=line.find('line')
    if checkifread==1:
        print "Read label found"
        #means we are on a read line
        currentread=line
    else:
        #We are on a sequence line for currentread.
        currentlength=len(line)
        print currentlength
    print top_read_line_length

    if int(top_read_line_length) < int(currentlength):
        print topreadline
        topreadline=currentread#now topreadline label is the "_line" string
        topreadlinelength=int(currentlength)
        print topreadline

        #go to next line

print "Done"
print "Longest line is...."
print topreadline

Ответы [ 12 ]

8 голосов
/ 21 октября 2011

Чтобы получить метку самой длинной строки, создайте отображение меток на длину строки

В вашем примере набора данных он выглядит как метка startwith "_line", и сразу следует соответствующая строка:

label2linelength = {}
for line in open('test.txt'):
    if line.startswith('_line '):
        label = line
    else:
        label2linelength[label] = len(line)
    lastline = line
print max(label2linelength.items(), key=lambda kv: kv[1])
8 голосов
/ 21 октября 2011

Если все, что вам нужно, это самая длинная строка в файле (как следует из заголовка вопроса), то в современном Python эта чертовски проста:

>>> max(open('test.txt'), key=len)
3 голосов
/ 21 октября 2011

Этого легко достичь:

data = open('test.txt').readlines()
max_line_pos = data.index(max(data, key=len))
prev_line = data[max_line_pos-1]
print prev_line
2 голосов
/ 29 октября 2011

Еще один краткий вариант:

from itertools import imap, izip
from operator import itemgetter
with open("a.py") as f:
    res = max(izip(f, imap(len, f)), key=itemgetter(1))[0]

При этом каждая вторая строка рассматривается как метка.

2 голосов
/ 21 октября 2011

Я бы уточнил ответ Раймонда;если бы grouper () был доступен в стандартной библиотеке lib, этот ответ снова был бы очень близок к oneliner;К сожалению, это не так, grouper определен только в примерах itertools.

Я думаю, вы бы предпочли эту версию, поскольку она функциональна.Я не проверял его работоспособность, но, по крайней мере, я не открываю файл и не ищу дважды, а также храню все содержимое в памяти.

from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

max( grouper(2, open("test.txt")), key=lambda x:len(x[1]))[0]
2 голосов
/ 21 октября 2011

Я бы сделал что-то вроде:

label = None
maxlen = 0
maxstr = ''
maxlabel = None
with open('f.txt') as f:
  for line in f:
    line = line.rstrip()
    if line.startswith('_line'):
      label = line
    elif len(line) > maxlen:
      maxlen = len(line)
      maxstr = line
      maxlabel = label
print maxlabel, maxstr

Это немного более обобщенно, чем формулировка проблемы, поскольку позволяет использовать несколько строк текста на ярлык.

1 голос
/ 24 октября 2011

Если вы уверены, что данные верны и не нуждаетесь в обработке ошибок, это должно сделать работу:

lines = open('test.txt', 'r').readlines()
print max([(len(lines[i+1]), lines[i])
           for i in xrange(0, len(lines), 2)])[1].strip()
1 голос
/ 21 октября 2011

Вот мой. Это работает, когда некоторые другие ответы здесь потерпят неудачу, например входной файл, такой как

_line 1
abc
_line 2
defg
_line 3
hij

Но это зависит от формата файла, как вы сказали.

with open('test.txt') as f:
  spam = f.readlines()

labels = spam[0::2]
lines = spam[1::2]

d = dict(zip(labels, lines))

longest_lines_label = max(d, key=lambda x: len(d[x]))

print "Longest line is...."
print longest_lines_label, d[longest_lines_label]
0 голосов
/ 28 октября 2011

Вот ваш исправленный код:

f = open('test.txt', 'r')
print f

read = None
top_read_line_length = 0
topreadline = None
currentlength = 0
label_line = True
for line in f:  
    if label_line:
        label_line = False
        print "label line", line
        #means we are on a read line
        currentread = line
    else:
        label_line = True
        #We are on a sequence line for currentread.
        currentlength = len(line)
        print 'cl', currentlength
    print top_read_line_length

    if top_read_line_length < currentlength:
        print 'trl', topreadline
        topreadline = currentread #now topreadline label is the "_line" string
        top_read_line_length = currentlength
        print 'trl', topreadline

        #go to next line

print "Done"
print "Longest line is...."
print topreadline

Я добавил label_line логическое значение для переключения между линиями меток и линиями данных, но важными составляющими были:

  • поместите достаточно информации в свои строки печати, чтобы увидеть, что происходит; и
  • соответствует вашим именам переменных

Проблема была в последнем if наборе - вы проверяли top_read_line_length, но устанавливали topreadlinelength (без подчеркиваний).

0 голосов
/ 21 октября 2011

А вот еще один способ:

import re, mmap

with open("test.txt", "rb") as f:
    mm = mmap.mmap(f.fileno(), 0, mmap.MAP_PRIVATE, mmap.PROT_READ)
    print max(re.finditer(r'_line (\d+)\n(.*)', mm),
              key=lambda m: len(m.group(2))).group(1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...