Как мне прочитать случайную строку из одного файла в Python? - PullRequest
32 голосов
/ 22 августа 2010

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

Ответы [ 11 ]

60 голосов
/ 22 августа 2010

Не встроенный, но алгоритм R(3.4.2) («Алгоритм водохранилища» Уотермана) из книги Кнута «Искусство компьютерного программирования» хорош (в очень упрощенной версии):

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

The num, ... in enumerate(..., 2) итератор создает последовательность 2, 3, 4 ... Следовательно, randrange будет 0 с вероятностью 1.0/num - и это вероятность, с которой мы должны заменить текущую выбранную строку (особый случайпример выборки 1 ссылочного алгоритма - см. книгу Кнута для доказательства правильности == и, конечно, мы также имеем дело с достаточно маленьким «резервуаром», чтобы поместиться в память; -)) ... и точновероятность, с которой мы делаем т.

27 голосов
/ 22 августа 2010
import random
lines = open('file.txt').read().splitlines()
myline =random.choice(lines)
print(myline)

Для очень длинного файла: искать случайное место в файле по его длине и находить два символа новой строки после позиции (или новой строки и конца файла).Сделайте еще раз 100 символов до или от начала файла, если исходная позиция поиска была <100, если мы оказались в последней строке. </p>

Однако это слишком сложно, так как файл является итератором. Так что составьте список и выберите случайный.choice (если вам нужно много, используйте random.sample):

import random
print(random.choice(list(open('file.txt'))))
9 голосов
/ 11 июля 2014

Хотя я опоздал на четыре года, я думаю, что у меня самое быстрое решение. Недавно я написал пакет 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))

Первый раз, когда это делается, является наихудшим, поскольку программа чтения строк должна скомпилировать выходной файл в специальном формате. После того, как это будет сделано, читатель может быстро получить доступ к любой строке из файла, независимо от размера файла.

Если ваш файл очень маленький (достаточно маленький, чтобы поместиться в МБ), то вы можете заменить dopen на copen, и он сделает кэшированную запись файла в памяти. Мало того, что это быстрее, но вы получите количество строк в файле, когда он загружен в память; это сделано для вас. Все, что вам нужно сделать, это сгенерировать случайный номер строки. Вот пример кода для этого.

from random import randint
from linereader import copen

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

Я просто очень обрадовался, потому что увидел кого-то, кто мог бы извлечь выгоду из моей посылки! Извините за мертвый ответ, но пакет определенно может быть применен ко многим другим проблемам.

9 голосов
/ 22 августа 2010

Это зависит от того, что вы подразумеваете под «слишком большими» накладными расходами. Если возможно сохранение всего файла в памяти, то что-то вроде

import random

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

сделает свое дело.

3 голосов
/ 31 января 2015

Если вы не хотите читать весь файл, вы можете искать в середине файла, затем искать в обратном порядке новую строку и вызывать readline.

Вот скрипт Python3что делает именно это,

Одним из недостатков этого метода является то, что короткие линии имеют меньшую вероятность появления.

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()
2 голосов
/ 15 апреля 2019

Немного улучшенная версия ответа Алекса Мартелли , который обрабатывает пустые файлы (возвращая значение 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) пространство.

2 голосов
/ 22 августа 2010

Найдите случайную позицию, прочитайте строку и отбросьте ее, затем прочитайте другую строку. Распределение линий не будет нормальным, но это не всегда имеет значение.

0 голосов
/ 10 июля 2019

Если вы не хотите загружать весь файл в ОЗУ с помощью 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

П.С .: Да, это было предложено Игнасио Васкесом-Абрамсом в его ответе выше, но а) в его ответе нет кода и б) я сам придумал эту реализацию; он может вернуть первую или последнюю строку. Надеюсь, что это может быть полезно для кого-то.

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

0 голосов
/ 03 мая 2018
import random

with open("file.txt", "r") as f:
    lines = f.readlines()
    print (random.choice(lines))
0 голосов
/ 06 декабря 2017

Это может быть громоздко, но это работает, я думаю?(по крайней мере, для текстовых файлов)

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

Он читает каждую строку файла и добавляет ее в список.Затем он выбирает случайную строку из списка.Если вы хотите удалить строку после ее выбора, просто сделайте

linelist.remove(choice)

Надеюсь, что это может помочь, но по крайней мере никаких дополнительных модулей и импортов (кроме случайных) и относительно легких.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...