为了澄清,如果我有一个包含8个元素的列表,我会想要随机选择2.如果我有一个包含20个元素的列表,我会想要随机选择5.我还想保证(尽管不需要) )两个元素不接触,即如果可能不接触3和4元素。相反,3和5会更好。
答案 0 :(得分: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";
答案 1 :(得分: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";