为了澄清,如果我有一个包含 8 个元素的列表,我想随机选择 2 个。如果我有一个包含 20 个元素的列表,我想随机选择 5 个。我还想保证(尽管不需要)两个元素不接触,即如果可能,不要接触 3 和 4 元素。相反,3和5会更好。
问问题
93 次
2 回答
3
最简单的解决方案:
- 随机播放列表
- 选择第一季度。
示例实现:
use List::Util qw/shuffle/;
my @nums = 1..20;
my @pick = (shuffle @nums)[0 .. 0.25 * $#nums];
say "@pick";
示例输出:10 2 18 3 19
.
您的附加限制“没有相邻数字”实际上会降低随机性,如果您想要实际随机性,则应避免使用。为了避免两个相邻元素包含在输出中,我会迭代地将不需要的元素拼接到列表中:
my @nums = 1..20;
my $size = 0.25 * @nums;
my @pick;
while (@pick < $size) {
my $i = int rand @nums;
push @pick, my $num = $nums[$i];
# check and remove neighbours
my $len = 1;
$len++ if $i < $#nums and $num + 1 == $nums[$i + 1];
$len++, $i-- if 0 < $i and $num - 1 == $nums[$i - 1];
splice @nums, $i, $len;
}
say "@pick";
于 2013-10-20T06:25:07.160 回答
0
use strict;
use warnings;
sub randsel {
my ($fact, $i, @r) = (1.0, 0);
while (@r * 4 < @_) {
if (not grep { $_ == $i } @r) {
$fact = 1.0;
# make $fact = 0.0 if you really don't want
# consecutive elements
$fact = 0.1 if grep { abs($i - $_) == 1 } @r;
push(@r, $i) if (rand() < 0.25 * $fact);
}
$i = ($i + 1) % @_;
}
return map { $_[$_] } sort { $a <=> $b } @r;
}
my @l;
$l[$_] = $_ for (0..19);
print join(" ", randsel(@l)), "\n";
于 2013-10-20T05:53:39.090 回答