从文件中随机读取一行?c#

7

我有一个包含几百行的文本文件,结构非常简单。

名 姓

我需要从文件中随机选择一个名字和姓氏并列出。


请发布您现在拥有的内容... - Hari Pachuveetil
2个回答

15
string[] lines = File.ReadAllLines(...); //i hope that the file is not too big
Random rand = new Random();
return lines[rand.Next(lines.Length)];

另一个(也许更好的)选项是使文件的第一行包含其中记录数,这样你就不必读取整个文件。


4
我讨厌别人在我之前回答我能够回答的问题,尤其是当他们使用与我相同的代码时 :) +1 - Callum Rogers
谢谢,我刚刚想通了。但是你的方法似乎更好。 - crap
只要文件相对较小,那么这个方法是可行的。我提供了一种替代方案,可以让你不必将整个文件保存在内存中。 - tvanfosson
@tvanfosson:如果文件非常大(通过在第一行添加记录数),第二个版本也可以工作。与您的解决方案相比(从数学角度我真的很喜欢它),它的优点是平均只读取文件的一半(每次仅将一行保存在内存中)。 - Itay Karo
对于“文件的第一行包含记录数量”的部分加1。 - Josh M.
不要在每次调用时分配 new Random(),如果这些调用在时间上太接近,结果将不会随机。应该使用线程静态的 Random。参见 Random number generator only generating one random number - dbc

13

读取每一行时,保持一个计数器N,表示当前已经读取了多少行。以1/N的概率选择每一行,即第一行始终被选中,第二行被选中的概率为1/2,替换第一行,第三行为1/3,依此类推。这样每一行都有1/N的概率成为被选中的行,你只需要一次性读取文件,并且不需要在任何给定时间将整个文件存储在内存中。

下面是一个可以根据你的需求进行调整的实现。

public string RandomLine( StreamReader reader )
{
    string chosen = null;
    int numberSeen = 0;
    var rng = new Random();
    while ((string line = reader.ReadLine()) != null)
    {
        if (rng.NextInt(++numberSeen) == 0)
        {
            chosen = line;
        }
    }
    return chosen;
}

基于一个C语言实现的代码 (链接),用于从任意长的链表中选择节点。


这里的数学很好,很漂亮 :) - Itay Karo
1
@Itay:啊,我现在有点明白了。在第n步中,你用概率(n-1)/n保留前一个选择。通过归纳法,前一个选择的概率是1/(n-1),因此乘以这个概率得到1/n。聪明。 - President James K. Polk
3
@GregS - 使用归纳推理。假设在第N步,每个元素被选择的概率为1/n。当N=1时,这是很清楚的。当N = 2时,第一个元素在第1步被选择,有1/2的概率在第2步被替换,所以我们的假设成立。现在在第n+1步,根据我们的假设,每个先前的元素都有1/n的机会被随机选择。以1/n+1的概率,我们选择要替换它。显然,当前元素有1/n+1的被选中概率,但该元素是随机选择的,因此所有先前的元素都有1/n的被选中概率。 - tvanfosson
实际上选择第 n 行的概率为 p(n) = (1/n)*(1 - i > n 的所有 p(i) 的和)。 - Itay Karo
不要在每次调用时分配 new Random(),如果调用发生得太接近,结果将不是随机的。应该使用线程静态的 Random。请参见 Random number generator only generating one random number - dbc
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接