使用perl,给定任意大小的数组,如何随机选择列表的1/4

时间:2013-10-20 05:26:47

标签: perl

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

2 个答案:

答案 0 :(得分:3)

最简单的解决方案:

  1. 随机播放列表
  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";
    

答案 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";