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?
Répondre
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.
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
Il existe déjà 'List :: Util :: shuffle'. Voir http://search.cpan.org/perldoc/List::Util#shuffle_LIST –
Il n'est pas nécessaire d'écrire votre propre 'shuffle' quand celui de List :: Util est plus robuste (et plus rapide). – friedo
Merci! Je suis en train d'éditer ma réponse maintenant. – dreeves
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.
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.
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.
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.
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
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.
Quel module DBM utilisez-vous? –
DBM standard en Perl 5.8.x construit pour Windows. Désolé, je n'ai pas plus de détails. – Paul