Есть ли встроенный метод? Если нет, то как я могу это сделать, не затрачивая слишком много накладных расходов?
Как читать случайную строку из одного файла в python?
Ответ 1
Не встроенный, но алгоритм 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 ссылочного алгоритма - см. книгу Кнута для доказательства правильности == и, конечно, мы также имеем дело с достаточно маленьким "резервуаром", чтобы уместиться в память; -))... и именно та вероятность, с которой мы это делаем.
Ответ 2
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'))))
Ответ 3
Это зависит от того, что вы подразумеваете под "слишком большими" накладными расходами. Если хранить весь файл в памяти, возможно, что-то вроде
import random
random_lines = random.choice(open("file").readlines())
сделал бы трюк.
Ответ 4
Хотя я опаздываю на четыре года, я думаю, что у меня есть самое быстрое решение. Недавно я написал пакет 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))
Я просто очень рад, потому что увидел кого-то, кто мог бы воспользоваться моим пакетом! Извините за мертвый ответ, но пакет определенно может быть применен ко многим другим проблемам.
Ответ 5
Если вы не хотите читать весь файл, вы можете искать его в середине файла, затем искать назад для новой строки и называть 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()
Ответ 6
Ищите случайную позицию, читайте строку и отбрасывайте ее, затем читайте другую строку. Распределение линий не будет нормальным, но это не всегда имеет значение.
Ответ 7
Немного улучшенная версия ответа Алекса Мартелли, которая обрабатывает пустые файлы (возвращая значение по default
):
from random import randrange
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)
.
Ответ 8
Вы можете добавить строки в набор(), который будет произвольно менять порядок.
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)
Ответ 9
Это может быть громоздким, но он работает, я думаю? (по крайней мере, для файлов 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)
Надеюсь, это может помочь, но, по крайней мере, никаких дополнительных модулей и импорта (кроме случайных) и относительно легкого.
Ответ 10
import random
with open("file.txt", "r") as f:
lines = f.readlines()
print (random.choice(lines))
Ответ 11
Если вы не хотите загружать весь файл в ОЗУ с помощью f.read()
или f.readlines()
, вы можете получить случайную строку следующим образом:
import os
import random
def get_random_line(filepath: str) -> str:
file_size = os.path.getsize(filepath)
with open(filepath, 'rb') as f:
while True:
pos = random.randint(0, file_size)
if not pos: # the first line is chosen
return f.readline().decode() # return str
f.seek(pos) # seek to random position
f.readline() # skip possibly incomplete line
line = f.readline() # read next (full) line
if line:
return line.decode()
# else: line is empty -> EOF -> try another position in next iteration
PS: да, это было предложено Игнасио Васкесом-Абрамсом в его ответе выше, но а) в его ответе нет кода и б) я сам придумал эту реализацию; он может вернуть первую или последнюю строку. Надеюсь, что это может быть полезно для кого-то.
Однако, если вы заботитесь о распространении, этот код не вариант для вас.