我正准备接受电话采访。我在互联网上遇到了这些问题。谁能告诉我一些好的答案?
假设我给你一个文本文件并要求你编写一个程序,该程序将从文件中返回一个随机行(所有行必须具有相同的返回概率)
与第1部分相同,但这次整个文本文件无法放入主存储器
与第2部分相同,但现在你有一个流而不是一个文件。
请帮忙。
好的...... @每个人,在我问到这个问题之前我真的有一些想法......看到我的同伴们的无情攻击,我发布了我的答案。请随意攻击他们......
1:计算文件中'\ n'的数量。生成1和数字之间的随机数,并返回数字-1'\ n'之后的行。
2:将文件逐个部分地存入主存储器,并按照上述步骤进行操作。
3:我对此并不太了解,并希望得到任何意见。
很棒的是你们真的给予灵感来推进......
答案 0 :(得分:22)
将所有行读入数组,返回1范围内的随机行和行数。
最简单:计算行数,随机选择行号,再次浏览文件并返回。
你只需要记住一行。每个新行的概率为1 / N(N为行读取)。
伪代码:
i = 1
chosen_line = ""
for line in lines:
if random() < 1/i: # random returns a uniform random number in [0,1)
chosen_line = line
i += 1
return chosen_line
算法编号3也可以用于1和2。
答案 1 :(得分:9)
您可以在不必读取内存中的所有行的情况下执行此操作,因此可以很好地处理大型文件。伪代码:
linenum := 0
ret := ''
while more lines to read:
line := readline()
linenum := linenum + 1
r := uniform_random(0, linenum)
if r < 1:
ret := line
return ret
证明:我们首先注意到我们始终在ret
中保存第一行。如果文件有一行,您将选择它,然后就完成了。
对于双行文件,ret
将在100%的时间内保存第一行,第二行将在循环的第二次迭代期间的ret
保存50%的时间。因此,每条线的概率为0.5。
现在,让我们假设此方法适用于≤N
行的文件。为了证明这意味着它适用于N+1
,在循环的(N+1)
次迭代中,有1/(N+1)
概率选择最后一行(random(0, N+1) < 1
有这种可能性)。因此,最后一行有1/(N+1)
被选中的概率。选择所有其他行的概率仍然相互相等,我们称之为x
。然后,N*x + 1/(N+1) == 1
,表示x = 1/(N+1)
。
感应证明已经完成。
编辑:糟糕,在回复之前没有看到第一个答案的第三个方法。不过,如果只是为了证明,我会在这里保留这篇文章,并且如果有任何错误,其他人有机会纠正它。
答案 2 :(得分:1)
Re 1:使用解决方案2
Re 2:您希望使用RandomAccessFile访问扫描整个文件以计算行数并(可能)缓存每行开头的文件指针。 然后你可以随机选择一个(我假设这个问题不是关于如何生成随机数)并回到那个起点,读取该行并返回它。 如果你想要它快,那么请确保你正在缓冲读数(否则raf是慢的)。
Re 3:如果流不适合内存(即你无法缓存整个内容)而你不知道流中有多少行而没有读取整个流(假设你只能阅读它曾经)然后我看不到解决方案。我也在等待答案...
答案 3 :(得分:-1)
#3:将流写入磁盘上的文件并使用解决方案2.当然,这不是最有效的解决方案,但非常简单。