Подтвердить что ты не робот

Как читать случайную строку из одного файла в python?

Есть ли встроенный метод? Если нет, то как я могу это сделать, не затрачивая слишком много накладных расходов?

4b9b3361

Ответ 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: да, это было предложено Игнасио Васкесом-Абрамсом в его ответе выше, но а) в его ответе нет кода и б) я сам придумал эту реализацию; он может вернуть первую или последнюю строку. Надеюсь, что это может быть полезно для кого-то.

Однако, если вы заботитесь о распространении, этот код не вариант для вас.