2010-01-27 82 views
1

我有一个Perl DBM哈希,其中包含一个我想从随机选取的URL列表以加载平衡蜘蛛网站点。因此,我想随机选择一个键,或者选择第n个元素(这样我可以随机选择n)。如何访问Perl DBM哈希中的随机元素?

我知道这违背了散列的概念,但这可能吗?

注意:错过了一个有价值的观点,即散列大小将会过大,无法加载所有要随机选择的键。

+0

您正在使用哪个DBM模块? – 2010-01-27 22:11:02

+0

针对Windows构建的Perl 5.8.x中的标准DBM。对不起,我没有更多的细节。 – Paul 2010-01-27 22:17:39

回答

1

当然,这是可能的。首先,获取密钥列表。然后,使用来自List::Utilshuffle随机化列表。

然后,循环按键。

如果密钥太多(因此将它们全部保存在列表中,并且不可能洗牌),请记住您正在使用并列哈希值。只需使用each即可遍历键值对。

订单将是确定性的,但AFAIK,它不会是字母或插入顺序。这本身就可能让你得到你想要的东西。

+0

感谢您的建议。不幸的是我的散列太大而无法加载所有的密钥。 – Paul 2010-01-27 22:31:18

+0

PaulMdx - 'each'通过散列迭代地返回一个键和一个值。所以,你可以一次处理一个。 – daotoad 2010-01-28 02:04:15

2

从数组中挑选一个随机元素更简单,因此您可以使用keys(%foo)来获取密钥数组并从中随机选取。

我相信这会从一个数组返回随机元素$x

$x = $array[rand @array]; 

如果你想洗牌的数组,考虑名单::的Util ::洗牌。请参阅http://search.cpan.org/perldoc/List::Util#shuffle_LIST

+1

已经有'List :: Util :: shuffle'。参见http://search.cpan.org/perldoc/List::Util#shuffle_LIST – 2010-01-27 22:19:56

+1

当List :: Util中的一个更健壮(更快)时,无需编写自己的'shuffle'。 – friedo 2010-01-27 22:19:59

+0

谢谢!我正在编辑我的答案。 – dreeves 2010-01-27 22:24:49

3

我不认为任何DBM软件包都有用于检索随机密钥或通过索引号检索密钥的API。您可以查找某个特定的密钥,也可以按照数据库选择的所有顺序读取所有密钥(如果数据库已修改,可能会发生变化,并且可能随机或不随机,无论您想要什么去做)。

你可以通读所有的键并选择一个,但是每次需要读取整个数据库(或者至少有相当一部分数据库),这可能太慢了。

我想你需要重新安排你的数据结构。

  1. 你可以使用一个真正的SQL数据库 (如SQLite),所以你可以 查找行都是由连续 行号和网址。这将是 是最灵活的。

  2. 您可以使用顺序整数 作为DBM文件的关键字。那 会随机挑选一个 容易,但你不能再通过URL查找 条目。

  3. 您可以使用两个DBM文件:一个是现在的文件,另一个是以URL为值的连续整数键入的。 (实际上,由于URL看起来不像整数,因此可以将两组记录存储在同一个DBM文件中,但这会使使用each的任何代码复杂化。)这将使用两倍的磁盘空间,并且会使插入/删除条目更复杂一些。除非由于某些原因无法安装SQLite,否则你可能会更好地使用方法#1。

+0

'真正的SQL数据库'的相关问题: http://stackoverflow.com/questions/19412/how-to-request-a-random-row-in-sql – plusplus 2010-01-28 09:34:58

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}}; 

这样就可以根据需要提取随机值。