2010-08-22 104 views
26

¿Hay un método incorporado para hacerlo? Si no, ¿cómo puedo hacer esto sin que me cueste demasiado?¿Cómo leo una línea aleatoria de un archivo en Python?

+0

@Greg That's Perl, no Python – quantumSoup

+2

@quantumSoup: La pregunta usa Perl en sus ejemplos, pero la pregunta es independiente del idioma. Las respuestas más útiles usan pseudocódigo, fácilmente traducido a su idioma de elección. –

+0

Gracias, también encontré esta ayuda mucho: http://mail.python.org/pipermail/tutor/2007-July/055635.html Aunque tienes que leerlos en la memoria. – Shane

Respuesta

51

No incorporado, pero algoritmo R(3.4.2) (Waterman "Reservoir Algoritmo") de Knuth de "The Art of Computer Programming" es bueno (en una versión muy simplificada):

import random 

def random_line(afile): 
    line = next(afile) 
    for num, aline in enumerate(afile): 
     if random.randrange(num + 2): continue 
     line = aline 
    return line 

El num + 2 produce la secuencia 2, 3, 4 ... El randrange será por lo tanto 0 con una probabilidad de 1.0/(num + 2) - y esa es la probabilidad con la que debemos reemplazar la línea seleccionada actualmente (el caso especial del tamaño de muestra 1 del algoritmo referenciado - ver El libro de Knuth como prueba de corrección == y, por supuesto, también estamos en el caso de un "depósito" lo suficientemente pequeño como para caber en la memoria; -) ... y exactamente la probabilidad con que nosotros do so.

+1

+1 para traducir de MIX a python – aaronasterling

+2

Este es un muestreo de yacimientos, ¿no? – HenryR

+6

Siempre he pensado que la función 'random.choice()' debería funcionar tanto en iteradores arbitrarios como en secuencias, implementando exactamente el algoritmo anterior. –

1

Busque una posición aleatoria, lea una línea y deséchela, luego lea otra línea. La distribución de líneas no será normal, pero eso no siempre importa.

+3

En particular, esto hace que sea imposible seleccionar la primera línea (así como elegir otras líneas con una probabilidad proporcional a la longitud de cada línea anterior). Mi A tampoco produce una distribución normal (eso sería raro, ¿qué significa, qué varianza?), Pero una uniforme, que parece algo más probable de cumplir con el significado del OP para "aleatorio". –

+0

Para solucionar el problema señalado por @AlexMartelli, elija la primera línea en caso de que la búsqueda aleatoria lo lleve a la última línea. Pero otro problema aquí es que una línea que tenga relativamente más palabras para otras líneas tendrá una mayor probabilidad de ser seleccionada. –

9

Depende de qué significa "demasiada" sobrecarga. Si es posible almacenar todo el archivo en la memoria, entonces algo como

import random 

random_lines = random.choice(open("file").readlines()) 

haría el truco.

23
import random 
lines = open('file.txt').read().splitlines() 
myline =random.choice(lines) 
print(myline) 

Para archivo muy largo: buscan lugar al azar en el archivo basado en su longitud y se encuentran dos caracteres de nueva línea después de la posición (o salto de línea y al final del archivo). Haga de nuevo 100 caracteres antes o desde el principio del archivo si la posición de búsqueda original fuera < 100 si terminamos dentro de la última línea.

Sin embargo, esto es más complicado, ya que el archivo es iterator.So que sea lista y tomar random.choice (si necesita muchos, random.sample uso):

import random 
print(random.choice(list(open('file.txt')))) 
+9

Si la tarea es leer solo una línea, no tiene sentido cargar el archivo completo en la memoria. – iankit

6

Aunque soy cuatro años de retraso, Creo que tengo la solución más rápida. Recientemente escribí un paquete de Python llamado linereader, que le permite manipular los punteros de los manejadores de archivos.

Aquí es la solución simple para conseguir una línea al azar con este paquete:

from random import randint 
from linereader import dopen 

length = #lines in file 
filename = #directory of file 

file = dopen(filename) 
random_line = file.getline(randint(1, length)) 

La primera vez que se hace esto es lo peor, como linereader tiene que compilar el archivo de salida en un formato especial. Una vez hecho esto, el lector de línea puede acceder rápidamente a cualquier línea del archivo, independientemente del tamaño del archivo.

Si su archivo es muy pequeño (lo suficientemente pequeño como para caber en un MB), puede reemplazar dopen con copen, y hace una entrada en caché del archivo dentro de la memoria. No solo es más rápido, sino que obtienes la cantidad de líneas dentro del archivo a medida que se carga en la memoria; está hecho para ti. Todo lo que necesitas hacer es generar el número de línea al azar. Aquí hay un código de ejemplo para esto.

from random import randint 
from linereader import copen 

file = copen(filename) 
lines = file.count('\n') 
random_line = file.getline(randint(1, lines)) 

¡Me puse muy feliz porque vi a alguien que podría beneficiarse de mi paquete! Perdón por la respuesta definitiva, pero el paquete definitivamente podría aplicarse a muchos otros problemas.

+0

Tuve la línea ValueError no. no encontrado, pero la línea no. era menor que el tamaño del archivo. – kakarukeys

2

Si no desea leer todo el archivo, puede buscar en el medio del archivo, luego buscar hacia atrás la nueva línea y llamar al readline.

Aquí es un script python3 la que hace precisamente esto,

Una desventaja de este método es líneas cortas tienen una menor likelyhood de aparecer.

def read_random_line(f, chunk_size=16): 
    import os 
    import random 
    with open(f, 'rb') as f_handle: 
     f_handle.seek(0, os.SEEK_END) 
     size = f_handle.tell() 
     i = random.randint(0, size) 
     while True: 
      i -= chunk_size 
      if i < 0: 
       chunk_size += i 
       i = 0 
      f_handle.seek(i, os.SEEK_SET) 
      chunk = f_handle.read(chunk_size) 
      i_newline = chunk.rfind(b'\n') 
      if i_newline != -1: 
       i += i_newline + 1 
       break 
      if i == 0: 
       break 
     f_handle.seek(i, os.SEEK_SET) 
     return f_handle.readline() 
0

Puede agregar las líneas en un conjunto() que va a cambiar su orden al azar.

filename=open("lines.txt",'r') 
f=set(filename.readlines()) 
filename.close() 

Para encontrar la primera línea:

print(next(iter(f))) 

Para encontrar la 3ª línea:

print(list(f)[2]) 

para enumerar todas las líneas en el conjunto:

for line in f: 
    print(line) 
0

Este puede ser voluminoso, pero funciona, supongo? (al menos para archivos txt)

import random 
choicefile=open("yourfile.txt","r") 
linelist=[] 
for line in choicefile: 
    linelist.append(line) 
choice=random.choice(linelist) 
print(choice) 

Lee cada línea de un archivo y lo agrega a una lista. Luego elige una línea aleatoria de la lista. Si desea eliminar la línea una vez que se ha elegido, simplemente

linelist.remove(choice) 

la esperanza que esto puede ayudar, pero al menos no hay módulos adicionales y las importaciones (aparte de azar) y relativamente ligero.

Cuestiones relacionadas