2010-01-27 2 views
1

У меня есть хеш-код Perl DBM, содержащий список URL-адресов, которые я хочу выбрать случайным образом, чтобы загрузить сайты spidering. В результате я хочу выбрать случайный ключ или выбрать n-й элемент (поэтому я могу случайным образом выбрать n).Как получить доступ к случайному элементу в хеш-стиле Perl DBM?

Я знаю, что это противоречит концепции хэша, но возможно ли это?

ПРИМЕЧАНИЕ. Пропущенная ценная точка, что размер хеша будет слишком большим, чтобы загрузить все клавиши, которые нужно выбрать случайным образом.

+0

Какой модуль DBM вы используете? –

+0

Стандартный DBM в Perl 5.8.x для Windows. Извините, у меня нет более подробной информации. – Paul

ответ

1

Конечно, это возможно. Сначала получите список ключей. Затем рандомизируйте список, используя shuffle от List::Util.

Затем, переверните ключи.

Если слишком много ключей (поэтому сохранить их все в списке и перетасовка невозможна), просто помните, что вы используете привязанные хэши. Просто используйте each для перебора пар ключей.

Заказ будет детерминированным, но AFAIK, он не будет в алфавитном порядке или порядке вставки. Это само по себе может помочь вам получить то, что вы хотите.

+0

Спасибо за совет. К сожалению, мой хэш слишком большой, чтобы загрузить все ключи. – Paul

+0

PaulMdx - 'each' возвращает ключ и значение, итеративно над хэшем. Таким образом, вы можете иметь дело с ними по одному. – daotoad

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 –

+1

Нет необходимости писать свой собственный 'shuffle', если один из List :: Util более надежный (и быстрее). – friedo

+0

Спасибо! Сейчас я редактирую свой ответ. – dreeves

3

Я не думаю, что в одном из пакетов DBM есть API для извлечения случайного ключа или для извлечения ключей по номеру индекса. Вы можете найти конкретный ключ, или вы можете прочитать все ключи в любом порядке, в котором база данных решит вернуть их (что может измениться, если база данных будет изменена, и может быть или не быть «случайным» достаточно для всего, что вы хотите делать).

Вы можете прочитать все ключи и выбрать один, но для этого потребуется считывать всю базу данных каждый раз (или, по крайней мере, значительную часть), и это, вероятно, слишком медленно.

Думаю, вам нужно будет изменить структуру данных.

  1. Вы можете использовать базу данных реального SQL (как SQLite), так что вы можете посмотреть строки как по порядковому номеру строки и URL. Это было бы самым гибким.

  2. В качестве ключа для вашего файла DBM можно использовать последовательное целое число . То, что сделает выбор случайного простым, но вы больше не можете искать записей по URL-адресу.

  3. Вы можете использовать два файла DBM: тот, который у вас есть сейчас, и второй ключ с последовательным целым числом с URL-адресом в качестве значения. (На самом деле, поскольку URL-адреса не похожи на целые числа, вы можете хранить оба набора записей в одном файле DBM, но это усложнит любой код, который использует each.) Это будет использовать в два раза больше места на диске и сделает вставку/удаление записей немного сложнее. Вероятно, вам будет лучше с подходом № 1, если вы не сможете установить SQLite по какой-то причине.

+0

связанный вопрос для «реальных баз данных SQL»: http://stackoverflow.com/questions/19412/how-to-request-a-random-row-in-sql – plusplus

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

С этим вы можете извлекать случайные значения по мере необходимости.

Смежные вопросы