是否有内置方法可以做到这一点?如果不能,如何在不花费太多开销的情况下做到这一点?
答案 0 :(得分:60)
不是内置的,但Knuth的“计算机编程艺术”中的算法R(3.4.2)
(Waterman的“水库算法”)很好(在一个非常简化的版本中):
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的特殊情况 - 请参阅Knuth的书以获得正确性证明==当然我们也是在一个足够小的“库”的情况下适合记忆; - ))......以及我们做的概率。
答案 1 :(得分:27)
import random
lines = open('file.txt').read().splitlines()
myline =random.choice(lines)
print(myline)
对于很长的文件: 根据它的长度寻找文件中的随机位置,并在位置(或换行符和文件结尾)之后找到两个换行符。如果原始搜索位置<100,如果我们在最后一行内部结束,则在文件开头之前或之后再做100个字符。
然而这很复杂,因为文件是iterator.So使它列出并取random.choice(如果你需要很多,请使用random.sample):
import random
print(random.choice(list(open('file.txt'))))
答案 2 :(得分:9)
这取决于“太多”开销是什么意思。如果可以将整个文件存储在内存中,那么就像
import random
random_lines = random.choice(open("file").readlines())
会做到这一点。
答案 3 :(得分:9)
虽然我迟到了四年,但我认为我有最快的解决方案。最近我写了一个名为linereader的python包,它允许你操作文件句柄的指针。
以下是使用此软件包获取随机行的简单解决方案:
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))
我真的很开心,因为我看到有人可以从我的包裹中受益!很抱歉这个死的答案,但该软件包肯定可以应用于许多其他问题。
答案 4 :(得分:3)
如果您不想阅读整个文件,可以搜索到文件的中间位置,然后向后搜索换行符,然后拨打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()
答案 5 :(得分:1)
寻找一个随机位置,读一行并丢弃它,然后读另一行。线条的分布不正常,但这并不总是重要的。
答案 6 :(得分:1)
Alex Martelli的answer的稍有改进,该版本处理空文件(通过返回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
此approach可用于使用O(n)
时间和O(1)
空间从任何迭代器中获取随机项目。
答案 7 :(得分:0)
您可以将这些行添加到set()中,这将随机更改其顺序。
filename=open("lines.txt",'r')
f=set(filename.readlines())
filename.close()
找到第一行:
print(next(iter(f)))
找到第3行:
print(list(f)[2])
列出集合中的所有行:
for line in f:
print(line)
答案 8 :(得分:0)
这可能很笨重,但我觉得它有效吗? (至少对于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)
希望这可能有所帮助,但至少没有额外的模块和导入(除了随机)和相对轻量级。
答案 9 :(得分:0)
import random
with open("file.txt", "r") as f:
lines = f.readlines()
print (random.choice(lines))
答案 10 :(得分:0)
如果您不想使用f.read()
或f.readlines()
将整个文件加载到RAM中,则可以通过以下方式获得随机行:
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
P.S .:是的,这是Ignacio Vazquez-Abrams在上面的答案中提出的,但是a)他的答案中没有代码,b)我自己想出了这个实现;它可以返回第一行或最后一行。希望对某人有用。
但是,如果您关心分发,那么此代码不是您的选择。
答案 11 :(得分:0)
import random
file = open('file.txt')
full_text = file.readlines()
random_text = random.choice(full_text)
print(random_text)