2010-01-27 5 views
1

J'ai un hachage Perl DBM contenant une liste d'URL que je veux sélectionner aléatoirement pour charger des sites spidering. En conséquence, je veux choisir une clé au hasard, ou sélectionnez le nième élément (donc je peux randomiser n). Je suis conscient que cela va à l'encontre du concept d'un hachage, mais est-ce possible? REMARQUE: vous avez manqué un point précieux indiquant que la taille de hachage sera trop grande pour charger toutes les clés à sélectionner de façon aléatoire.Comment accéder à un élément aléatoire dans un hachage Perl DBM?

+0

Quel module DBM utilisez-vous? –

+0

DBM standard en Perl 5.8.x construit pour Windows. Désolé, je n'ai pas plus de détails. – Paul

Répondre

1

Bien sûr, c'est possible. D'abord, obtenez une liste des clés. Ensuite, randomiser la liste, en utilisant shuffle de List::Util.

Ensuite, bouclez les touches.

S'il y a trop de clés (en les gardant toutes dans une liste et que le mélange n'est pas possible), souvenez-vous simplement que vous utilisez des hachages liés. Utilisez simplement each pour parcourir les paires de valeurs clés.

L'ordre sera déterministe mais AFAIK, il ne sera pas alphabétique ou ordre d'insertion. Cela, en soi, pourrait être en mesure de vous obtenir ce que vous voulez.

+0

Merci pour le conseil. Malheureusement, mon hash est trop gros pour charger toutes les clés. – Paul

+0

PaulMdx - 'each' renvoie une clé et une valeur, itérativement sur le hachage. Ainsi, vous pouvez traiter avec eux un à la fois. – daotoad

2

La sélection d'un élément aléatoire dans un tableau est plus simple, de sorte que vous pouvez utiliser keys(%foo) pour obtenir le tableau de clés et en tirer au hasard.

Je crois que cela renvoie un élément aléatoire $x d'un tableau:

$x = $array[rand @array]; 

Si vous voulez mélanger un tableau, pensez à List :: Util :: lecture aléatoire. Voir http://search.cpan.org/perldoc/List::Util#shuffle_LIST

+1

Il existe déjà 'List :: Util :: shuffle'. Voir http://search.cpan.org/perldoc/List::Util#shuffle_LIST –

+1

Il n'est pas nécessaire d'écrire votre propre 'shuffle' quand celui de List :: Util est plus robuste (et plus rapide). – friedo

+0

Merci! Je suis en train d'éditer ma réponse maintenant. – dreeves

3

Je ne pense pas que l'un des paquets DBM ait une API pour récupérer une clé aléatoire, ou pour récupérer des clés par numéro d'index. Vous pouvez rechercher une clé particulière, ou vous pouvez lire toutes les clés dans l'ordre choisi par la base de données pour les retourner (ce qui peut changer si la base de données est modifiée, et peut être "aléatoire" assez pour ce que vous voulez faire).

Vous pouvez lire toutes les clés et en choisir une, mais cela nécessiterait de lire la base de données entière à chaque fois (ou au moins une partie importante de celle-ci), et c'est probablement trop lent.

Je pense que vous devrez réorganiser votre structure de données.

  1. Vous pouvez utiliser une véritable base de données SQL (comme SQLite), vous pouvez donc rechercher des lignes à la fois par un nombre de ligne séquentielle et par URL. Ce serait être le plus flexible.

  2. Vous pouvez utiliser un entier séquentiel comme clé pour votre fichier DBM. Que rendrait la sélection aléatoire facile, mais vous ne pouvez plus regarder up entrées par URL.

  3. Vous pouvez utiliser deux fichiers DBM: celui que vous avez maintenant et un second entré par un entier séquentiel avec l'URL comme valeur. (En fait, comme les URL ne ressemblent pas à des entiers, vous pouvez stocker les deux ensembles d'enregistrements dans le même fichier DBM, mais cela compliquera tout code utilisant each.Cela utiliserait deux fois l'espace disque et rendrait l'insertion/suppression d'entrées un peu plus compliquée. Vous serez probablement mieux avec l'approche n ° 1, sauf si vous ne pouvez pas installer SQLite pour une raison quelconque.

+0

question connexe pour les «bases de données SQL réelles»: http://stackoverflow.com/questions/19412/how-to-request-a-random-row-in-sql – plusplus

1

Vous pouvez utiliser DBM::Deep au lieu d'un fichier DB traditionnel pour conserver vos données.

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

Avec cela, vous pouvez extraire des valeurs aléatoires si nécessaire.

Questions connexes