use List::Util; sub unique_random_list { my ($from, $to, $count) = @_; $count = List::Util::min ($count, $to - $from); my @result; my @queue = [ $from, $to - $from, $count ]; while (my $job = shift @queue) { my ($from, $length, $count) = @$job; if ($count == $length) { push @result, $from .. $from + $length; } elsif ($count == 1) { push @result, $from + int rand $length; } else { my $split_length = int ($length / 2); my $split_count = List::Util::min (int rand $count, $split_length); my $pad_length = $length - $split_length; my $pad_count = $count - $split_count; $split_count += $pad_count - $pad_length if $pad_count > $pad_length; unshift @queue, grep $_->[2], [ $from, $split_length, $split_count ], [ $from + $split_length, $length - $split_length, $count - $split_count ]; } } @result; } my @list = unique_random_list (10, 100, 30);