0

为了澄清,如果我有一个包含 8 个元素的列表,我想随机选择 2 个。如果我有一个包含 20 个元素的列表,我想随机选择 5 个。我还想保证(尽管不需要)两个元素不接触,即如果可能,不要接触 3 和 4 元素。相反,3和5会更好。

4

2 回答 2

3

最简单的解决方案:

  1. 随机播放列表
  2. 选择第一季度。

示例实现:

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 回答