- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我熟悉 the algorithm for reading a single random line from a file without reading the whole file into memory .我想知道是否可以将此技术扩展到 N 个随机行?
用例是一个密码生成器,它连接从字典文件中提取的 N 个随机单词,每行一个单词(如 /usr/share/dict/words
)。您可能会想到 angela.ham.lewis.pathos
。现在它将整个字典文件读入一个数组,并从该数组中随机选择 N 个元素。我想删除数组或文件的任何其他内存存储,并且只读取文件一次。
(不,这不是实际的优化练习。我对算法很感兴趣。)
更新:谢谢大家的回答。
答案分为三类:修改完整读取算法、随机查找或索引行并随机查找它们。
随机搜索要快得多,并且相对于文件大小是恒定的,但根据文件大小而不是单词数进行分配。它还允许重复(可以避免但它使算法 O(inf))。这是我使用该算法重新实现的密码生成器。我意识到通过从搜索点向前而不是向后读取,如果搜索落在最后一行,它会出现一个差一个错误。更正留给编辑作为练习。
#!/usr/bin/perl -lw
my $Words = "/usr/share/dict/words";
my $Max_Length = 8;
my $Num_Words = 4;
my $size = -s $Words;
my @words;
open my $fh, "<", $Words or die $!;
for(1..$Num_Words) {
seek $fh, int rand $size, 0 or die $!;
<$fh>;
my $word = <$fh>;
chomp $word;
redo if length $word > $Max_Length;
push @words, $word;
}
print join ".", @words;
然后是 Guffa 的答案,这正是我一直在寻找的;原始算法的扩展。较慢,它必须读取整个文件,但按字分配,允许在不改变算法效率的情况下进行过滤,并且(我认为)没有重复项。
#!/usr/bin/perl -lw
my $Words = "/usr/share/dict/words";
my $Max_Length = 8;
my $Num_Words = 4;
my @words;
open my $fh, "<", $Words or die $!;
my $count = 0;
while(my $line = <$fh>) {
chomp $line;
$count++;
if( $count <= $Num_Words ) {
$words[$count-1] = $line;
}
elsif( rand($count) <= $Num_Words ) {
$words[rand($Num_Words)] = $line;
}
}
print join ".", @words;
最后,索引和搜索算法具有按字而不是文件大小分布的优点。缺点是它读取整个文件并且内存使用量与文件中的字数成线性关系。不妨使用 Guffa 的算法。
最佳答案
在那个例子中,算法没有以非常好的和清晰的方式实现......一些更好地解释它的伪代码是:
cnt = 0
while not end of file {
read line
cnt = cnt + 1
if random(1 to cnt) = 1 {
result = line
}
}
如您所见,这个想法是您读取文件中的每一行并计算该行应被选中的概率。读完第一行概率为100%,读完第二行概率为50%,以此类推。
这可以扩展为通过保留大小为 N 的数组而不是单个变量来选择 N 项,并计算一行替换数组中当前行之一的概率:
var result[1..N]
cnt = 0
while not end of file {
read line
cnt = cnt + 1
if cnt <= N {
result[cnt] = line
} else if random(1 to cnt) <= N {
result[random(1 to N)] = line
}
}
编辑:
下面是用 C# 实现的代码:
public static List<string> GetRandomLines(string path, int count) {
List<string> result = new List<string>();
Random rnd = new Random();
int cnt = 0;
string line;
using (StreamReader reader = new StreamReader(path)) {
while ((line = reader.ReadLine()) != null) {
cnt++;
int pos = rnd.Next(cnt);
if (cnt <= count) {
result.Insert(pos, line);
} else {
if (pos < count) {
result[pos] = line;
}
}
}
}
return result;
}
我通过运行该方法 100000 次来进行测试,从 20 行中选择 5 行,并计算这些行的出现次数。这是结果:
25105
24966
24808
24966
25279
24824
25068
24901
25145
24895
25087
25272
24971
24775
25024
25180
25027
25000
24900
24807
如您所见,分布非常好。 :)
(我在运行测试时将 Random
对象的创建移到了方法之外,以避免因为种子取自系统时钟而出现种子问题。)
注意:
如果您希望它们随机排序,您可能想要打乱结果数组中的顺序。由于前 N 行在数组中是按顺序放置的,所以如果它们留在末尾则不会随机放置。例如,如果 N 大于或等于 3,并且选择了第三行,它将始终位于数组中的第三个位置。
编辑 2:
我更改了代码以使用 List<string>
而不是 string[]
.这使得以随机顺序插入前 N 个项目变得容易。我从新的测试运行中更新了测试数据,因此您可以看到分布仍然很好。
关于algorithm - 如何在不将文件存储在内存中的情况下从文件中读取 N 个随机行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/779797/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!