Как я могу случайно выбрать содержимое файла? - PullRequest
3 голосов
/ 23 июня 2009

У меня есть файл с содержимым

abc
def
high
lmn
...
...

В файлах более 2 миллионов строк. Я хочу случайным образом выбрать строки из файлов и вывести 50К строк. Есть мысли о том, как подойти к этой проблеме? Я думал в духе Perl и его функции rand (или удобная команда оболочки была бы аккуратной).

Похожие (возможно, повторяющиеся) вопросы:

Ответы [ 5 ]

12 голосов
/ 24 июня 2009

Предполагая, что вы в основном хотите вывести около 2,5% всех строк, это будет делать:

print if 0.025 > rand while <$input>;
5 голосов
/ 24 июня 2009

Оболочка способ:

sort -R file | head -n 50000
3 голосов
/ 24 июня 2009

С perlfaq5: «Как выбрать случайную строку из файла?»


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

Вот алгоритм отбора проб из книги верблюдов:

srand;
rand($.) < 1 && ($line = $_) while <>;

Это имеет значительное преимущество в пространстве перед чтением всего файла. Вы можете найти доказательство этого метода в Искусство компьютерного программирования , том 2, раздел 3.4.2, Дональдом Э. Кнут.

Вы можете использовать модуль File :: Random, который предоставляет функцию для этого алгоритма:

use File::Random qw/random_line/;
my $line = random_line($filename);

Другой способ - использовать модуль Tie :: File, который обрабатывает весь файл как массив. Просто получите доступ к элементу случайного массива.

2 голосов
/ 24 июня 2009

Perl way:

использовать CPAN. Есть модуль File :: RandomLine , который делает именно то, что вам нужно.

2 голосов
/ 24 июня 2009

Если вам нужно извлечь точное количество строк:

use strict;
use warnings;

# Number of lines to pick and file to pick from
# Error checking omitted!
my ($pick, $file) = @ARGV;

open(my $fh, '<', $file)
    or die "Can't read file '$file' [$!]\n";

# count lines in file
my ($lines, $buffer);
while (sysread $fh, $buffer, 4096) {
    $lines += ($buffer =~ tr/\n//);
}

# limit number of lines to pick to number of lines in file
$pick = $lines if $pick > $lines;

# build list of N lines to pick, use a hash to prevent picking the
# same line multiple times
my %picked;
for (1 .. $pick) {
    my $n = int(rand($lines)) + 1;
    redo if $picked{$n}++
}

# loop over file extracting selected lines
seek($fh, 0, 0);
while (<$fh>) {
    print if $picked{$.};
}
close $fh;
...