我有一个Perl DBM哈希,其中包含我想从中随机选择的URL列表以加载平衡抓取站点。结果我想随机选择一个键,或者选择第n个元素(所以我可以随机选择n)。
我知道这违反了哈希的概念,但这可能吗?
注意:错过了一个有价值的观点,即散列大小太大,无法加载随机选择的所有键。
答案 0 :(得分:3)
我认为任何DBM软件包都没有用于检索随机密钥的API,或者用于按索引号检索密钥的API。您可以查找特定的密钥,或者您可以按照数据库选择的任何顺序读取所有密钥(如果数据库被修改,则可能会更改,并且可能或可能不是“随机”足以满足您的任何需要做)。
你可以通读所有的键并选择一个,但这需要每次都读取整个数据库(或至少相当大一部分),这可能太慢了。
我认为您需要重新安排数据结构。
您可以使用真正的SQL数据库 (比如SQLite),所以你可以 按顺序查找行 行号和URL。这个会 是最灵活的。
您可以使用顺序整数 作为DBM文件的密钥。那 会选择一个随机的 容易,但你再也看不到了 按URL输入条目。
您可以使用两个DBM文件:您现在拥有的文件和第二个按顺序整数键入的文件,其中URL为值。 (实际上,由于URL看起来不像整数,因此您可以将两组记录存储在同一个DBM文件中,但这会使使用each
的任何代码复杂化。)这将使用两倍的磁盘空间,并且使插入/删除条目更复杂一些。方法#1你可能会更好,除非你出于某种原因无法安装SQLite。
答案 1 :(得分:2)
从数组中选取一个随机元素比较简单,因此您可以使用keys(%foo)
来获取键数组并从中随机选择。
我相信这会从数组中返回一个随机元素$x
:
$x = $array[rand @array];
如果要重新排列数组,请考虑List :: Util :: shuffle。见http://search.cpan.org/perldoc/List::Util#shuffle_LIST
答案 2 :(得分:1)
当然,这是可能的。首先,获取密钥列表。然后,使用List::Util中的shuffle
随机化列表。
然后,循环键。
如果键太多(所以将它们全部保存在列表中并且无法进行洗牌),请记住您正在使用绑定哈希。只需使用each
迭代键值对即可。
订单将是确定性的但是AFAIK,它不会按字母或插入顺序排列。这本身就可以让你得到你想要的东西。
答案 3 :(得分:1)
您可以使用DBM::Deep代替传统的DB文件来保存数据。
tie %hash, "DBM::Deep", {
file => "foo.db",
locking => 1,
autoflush => 1
};
# $hash{keys} = [ ... ]
# $hash{urls} = { ... } <- same as your current DB file.
my $like_old = $hash{urls}; # a ref to a hash you can use like your old hashref.
my $count = @{$hash{keys}};
有了它,您可以根据需要提取随机值。