2010-01-27 54 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}}; 

這樣就可以根據需要提取隨機值。