Если файл достаточно мал, считайте пары строк в память и выберите случайным образом из этой структуры данных.Если файл слишком большой, Евгений Y дает правильный ответ: используйте отбор проб из резервуара .
Вот интуитивное объяснение алгоритма.
Process the file line by line.
pick = line, with probability 1/N, where N = line number
Другими словамив строке 1 мы выберем строку 1 с вероятностью 1/1
.В строке 2 мы изменим выбор к строке 2 с вероятностью 1/2
.В строке 3 мы изменим выбор на строку 3 с вероятностью 1/3
.И т. Д.
Для наглядного доказательства представьте файл из 3 строк:
1 Pick line 1.
/ \
.5 .5
/ \
2 1 Switch to line 2?
/ \ / \
.67 .33 .33 .67
/ \ / \
2 3 1 Switch to line 3?
Вероятность для каждого результата:
Line 1: .5 * .67 = 1/3
Line 2: .5 * .67 = 1/3
Line 3: .5 * .33 * 2 = 1/3
Оттуда остальноеиндукция.Например, предположим, что файл имеет 4 строки.Мы уже убедились в том, что по состоянию на строке 3 каждая строка (1, 2, 3) будет иметь равные шансы быть нашим текущим выбором.Когда мы перейдем к строке 4, у нее будет 1/4
шанс быть выбранным - именно таким, каким он должен быть, таким образом уменьшая вероятности на предыдущих 3 строках точно на правильную величину (1/3 * 3/4 = 1/4
).
Вот ответ на вопрос Perl , адаптированный к вашей проблеме.
use strict;
use warnings;
# Ignore 5 lines.
<> for 1 .. 5;
# Use reservoir sampling to select pairs from remaining lines.
my (@picks, $n);
until (eof){
my @lines;
$lines[$_] = <> for 0 .. 1;
$n ++;
@picks = @lines if rand($n) < 1;
}
print @picks;