Obtenga información de la última línea de una instrucción if else dentro de un bucle for de Python

No creo que esto sea posible, pero pensé que preguntaría por si acaso. Así que estoy tratando de escribir un progtwig de python con eficiencia de memoria para analizar archivos que normalmente tienen más de 100 conciertos. Lo que estoy tratando de hacer es usar un bucle for para leer en una línea, dividir en varios caracteres varias veces y escribir todo dentro del mismo bucle.

El truco es que el archivo tiene líneas que comienzan con “#”, lo cual no es importante, excepto la última línea que comienza con “#”, que es el encabezado del archivo. Quiero poder extraer información de esa última línea porque contiene los nombres de muestra.

for line in seqfile: line = line.rstrip() if line.startswith("#"): continue (unless its the last line that starts with #) SampleNames = lastline[8:-1] newheader.write(New header with sample names) else: columns = line.split("\t") then do more splitting then write 

Si esto no es posible, entonces la única otra alternativa que se me ocurre es almacenar las líneas con # (que aún puede tener 5 gigas de tamaño), luego volver y escribir al principio del archivo, lo cual creo que no puede ser. hecho directamente, pero si hay una manera de hacer esa memoria de manera eficiente sería bueno.

Cualquier ayuda sería muy apreciada.

Gracias

Si desea que el índice de la última línea comience con # , lea una vez usando takewhile , consumiendo líneas hasta que llegue a la primera línea que no comience con # luego busque y use itertools.islice para obtener la línea:

 from itertools import takewhile,islice with open(file) as f: start = sum(1 for _ in takewhile(lambda x: x[0] == "#",f)) -1 f.seek(0) data = next(islice(f,start, start+1)) print(data) 

El primer argumento de takewhile es un predicado que, si bien el predicado es verdadero, takewhile tomará elementos del iterable pasado como segundo argumento, porque un objeto de archivo devuelve su propio iterador cuando consumimos el objeto takewhile utilizando la sum que ahora apunta el puntero del archivo. a la siguiente línea después de la línea de encabezado que desea, por lo que es solo una cuestión de buscar hacia atrás y obtener la línea con islice. Obviamente, también puede buscar mucho menos si solo desea volver a la línea anterior y tomar algunas líneas con el filtro de filetes hasta llegar a la última línea que comienza con un # .

expediente:

 ### ## # i am the header blah blah blah 

Salida:

  # i am the header 

La única forma de memoria eficiente que podría pensar si la línea podría estar en cualquier lugar significaría leer el archivo una vez que siempre se actualice una variable de índice cuando haya una línea que comience con #, luego podría pasar el archivo a la línea como en la respuesta anterior o usar linecache .getline como en esta respuesta:

 import linecache with open(file) as f: index = None for ind, line in enumerate(f, 1): if line[0] == "#": index = ind data = linecache.getline(file, index) print(data) 

Usamos un índice de inicio de 1 con enumerar como recuentos de línea de getline partir de 1 .

O simplemente actualice los datos variables que mantendrán cada línea comenzando con un # si solo desea esa línea en particular y no le importa la posición u otras líneas:

 with open(file) as f: data = None for line in f: if line[0] == "#": data = line print(data) # will be last occurrence of line starting with `#` 

O usando file.tell , manteniendo la posición del puntero anterior y usándola para buscar, luego llame al siguiente archivo de objeto para obtener las líneas / líneas que deseamos:

 with open(file) as f: curr_tell, prev_tell = None, None for line in iter(f.readline, ""): if line[0] == "#": curr_tell = prev_tell prev_tell = f.tell() f.seek(curr_tell) data = next(f) print(data) # i am the header 

También está la receta de consumo del código de itertools que podría usar para consumir el iterador del archivo hasta su índice de línea de encabezado -1, luego simplemente llame al siguiente en el objeto de archivo:

 def consume(iterator, n): "Advance the iterator n-steps ahead. If n is none, consume entirely." # Use functions that consume iterators at C speed. if n is None: # feed the entire iterator into a zero-length deque collections.deque(iterator, maxlen=0) else: # advance to the empty slice starting at position n next(islice(iterator, n, n), None)