Есть ли встроенный метод? Если нет, то как я могу это сделать, не затрачивая слишком много накладных расходов?
Не встроенный, но алгоритм R(3.4.2)
(Waterman "Reservoir Algorithm") от Knuth "Искусство компьютерного программирования" хорош (в очень упрощенной версии):
import random
def random_line(afile):
line = next(afile)
for num, aline in enumerate(afile, 2):
if random.randrange(num): continue
line = aline
return line
Итератор num,... in enumerate(..., 2)
создает последовательность 2, 3, 4... Следовательно, randrange
будет равен 0 с вероятностью 1.0/num
- и той вероятностью, с которой мы должны заменить текущую выбранную строку (особый случай с размером выборки 1 ссылочного алгоритма - см. книгу Кнута для доказательства правильности == и, конечно, мы также имеем дело с достаточно маленьким "резервуаром", чтобы уместиться в память; -))... и именно та вероятность, с которой мы это делаем.
import random
lines = open('file.txt').read().splitlines()
myline =random.choice(lines)
print(myline)
Для очень длинного файла: искать случайное место в файле на основе его длины и находить два символа новой строки после позиции (или новой строки и конца файла). Повторите 100 символов до или с начала файла, если исходная позиция поиска была < 100, если мы оказались внутри последней строки.
Однако это сложнее, так как файл является итератором. Так что сделайте список и возьмите random.choice(если вам нужно много, используйте random.sample):
import random
print(random.choice(list(open('file.txt'))))
Это зависит от того, что вы подразумеваете под "слишком большими" накладными расходами. Если хранить весь файл в памяти, возможно, что-то вроде
import random
random_lines = random.choice(open("file").readlines())
сделал бы трюк.
Хотя я опаздываю на четыре года, я думаю, что у меня есть самое быстрое решение. Недавно я написал пакет python под названием linereader, который позволяет вам манипулировать указателями дескрипторов файлов.
Вот простое решение для получения случайной строки с этим пакетом:
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))
В первый раз это делается хуже всего, так как linereader должен скомпилировать выходной файл в специальном формате. После этого linereader может быстро получить доступ к любой строке из файла, независимо от размера файла.
Если ваш файл очень мал (достаточно мал, чтобы вписаться в MB), вы можете заменить dopen
на copen
и сделать кэшированную запись файла в памяти. Это происходит не только быстрее, но вы получаете количество строк в файле, поскольку оно загружается в память; это делается для вас. Все, что вам нужно сделать, это создать случайный номер строки. Вот пример кода для этого.
from random import randint
from linereader import copen
file = copen(filename)
lines = file.count('\n')
random_line = file.getline(randint(1, lines))
Я просто очень рад, потому что увидел кого-то, кто мог бы воспользоваться моим пакетом! Извините за мертвый ответ, но пакет определенно может быть применен ко многим другим проблемам.
Если вы не хотите читать весь файл, вы можете искать его в середине файла, затем искать назад для новой строки и называть readline
.
Вот Python3 script, который делает именно это,
Один из недостатков этого метода заключается в том, что короткие линии имеют меньшее вероятность появления.
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()
import random
with open("file.txt", "r") as f:
lines = f.readlines()
print (random.choice(lines))
Ищите случайную позицию, читайте строку и отбрасывайте ее, затем читайте другую строку. Распределение линий не будет нормальным, но это не всегда имеет значение.
Немного улучшенная версия ответа Алекса Мартелли, которая обрабатывает пустые файлы (возвращает значение по default
):
def random_line(afile, default=None):
line = default
for i, aline in enumerate(afile, start=1):
if randrange(i) == 0: # random int [0..i)
line = aline
return line
Этот подход можно использовать для получения случайного элемента из любого итератора, использующего время O(n)
и пространство O(1)
.
Это может быть громоздким, но он работает, я думаю? (по крайней мере, для файлов txt)
import random
choicefile=open("yourfile.txt","r")
linelist=[]
for line in choicefile:
linelist.append(line)
choice=random.choice(linelist)
print(choice)
Он считывает каждую строку файла и добавляет его в список. Затем он выбирает случайную строку из списка. Если вы хотите удалить строку после ее выбора, просто сделайте
linelist.remove(choice)
Надеюсь, это может помочь, но, по крайней мере, никаких дополнительных модулей и импорта (кроме случайных) и относительно легкого.
Вы можете добавить строки в набор(), который будет произвольно менять порядок.
filename=open("lines.txt",'r')
f=set(filename.readlines())
filename.close()
Чтобы найти 1-ю строку:
print(next(iter(f)))
Чтобы найти третью строку:
print(list(f)[2])
Чтобы перечислить все строки в наборе:
for line in f:
print(line)