Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
I know the common idiom of getting a random array element: $array[int rand @array];. I can then extend that to return a random number of elements: @array[0 .. int rand @array];. But I need to also sometimes get 0 elements. Is there a more succinct way than to have two statements like this? my @subset = @array[0 .. int rand(1 + @array); @subset = () if @subset > @array;
Re: Idiom to return 0 or random number of array elements
by LanX (Saint) on Dec 07, 2012 at 05:48 UTC
|
DB<130> @array=a..c
=> ("a", "b", "c")
DB<131> @array[0 .. -1 + int rand 1+ @array]
=> ()
DB<132> @array[0 .. -1 + int rand 1+ @array]
=> ("a", "b")
DB<133> @array[0 .. -1 + int rand 1+ @array]
=> ("a")
DB<134> @array[0 .. -1 + int rand 1+ @array]
=> ("a", "b", "c")
DB<135> @array[0 .. -1 + int rand 1+ @array]
=> ("a", "b")
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Perfect, that's what I was looking for. Guess I was close, though. Thanks!
| [reply] [Watch: Dir/Any] |
Re: Idiom to return 0 or random number of array elements
by davido (Cardinal) on Dec 07, 2012 at 06:18 UTC
|
LanX got to the @slice[ 0 .. -1 ] solution ahead of me, but I'm thinking you might still be missing something.
In your first example, "$element = $array[int rand @array];", you're selecting a random element. In your second example, "@elements = @array[0 .. int rand @array];" you're selecting a random number of elements, but the elements being selected are not random except for the quantity. If your array contains "a, b, c, d, e", you'll get "a", or "a,b", or "a,b,c", etc. Even after dealing with the ability to get no elements at all, you're still not actually getting random elements.
Maybe that's what you want. Or maybe you want a random number of random elements (with no duplicates). If that's the case, you might just shuffle:
use List::Util 'shuffle';
use List::MoreUtils 'minmax';
my @array = 'a' .. 'z';
my @quantities;
for( 1 .. 100 ) {
# --------------------This is the solution line: -------------------
+----------
my @selected = @{ [ shuffle @array ] }[ 0 .. int( rand @array + 1 )
+- 1 ];
# ------------------------------------------------------------------
+------
push @quantities, my $quantity = @selected;
print "@selected => ($quantity)\n";
}
print "\nMin/Max elements: (", join( ',', minmax @quantities ), ")\n";
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Idiom to return 0 or random number of array elements
by bart (Canon) on Dec 07, 2012 at 12:08 UTC
|
my @subset = @array[0 .. int rand(1 + @array)-1];
If the second parameter for the .. operator is lower than the first parameter, then you'll get no items.
BTW this will not return a random number of random elements. Instead it'll return the first N elements where N is a random number. If you want random elements, you could shuffle the array first. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Idiom to return 0 or random number of array elements
by BrowserUk (Patriarch) on Dec 07, 2012 at 05:37 UTC
|
@array = 0 .. 9;;
sub x{ return @array[ 0 .. int( rand @array ) ]; };;
$stats{ scalar( x() ) }++ for 1 .. 1000;;
pp \%stats;;
{ "0" => 90, 1 => 103, 2 => 126, 3 => 99, 4 => 101, 5 => 101, 6 => 88,
+ 7 => 97, 8 => 105, 9 => 90 }
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
RIP Neil Armstrong
Computers are making people easier to use everydaydiv | [reply] [Watch: Dir/Any] [d/l] [select] |
|
@array[0 ..0] is one and not zero elements!
DB<103> @array=a..f
=> ("a", "b", "c", "d", "e", "f")
DB<104> @array[0..0]
=> "a"
UPDATE:
your statistical proof falls into the trap
scalar @array != scalar (LIST)
if your function() returns a one element list (0), then scalar function() will be 0, since 0 is the last element of the list.
(more detailed in Re^2: Idiom to return 0 or random number of array elements by eyepopslikeamosquito )
initializing @array = 1..10 makes it more obvious, b/c the last element of a sublist is now identical to the length!
DB<106> @array = 1 .. 10;
=> (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
DB<107> sub x{ return @array[ 0 .. int( rand @array ) ]; };
=> 0
DB<108> $stats{ scalar( x() ) }++ for 1 .. 1000;
=> ""
DB<109> \%stats;
=> { 1 => 100, 2 => 101, 3 => 108, 4 => 108, 5 => 101, 6 => 103, 7 =>
+ 79, 8 => 98, 9 => 100, 10 => 102 }
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
$stats{ scalar( x() ) }++
That is, this:
$stats{ x() }++
produces numbers in the 0..9 range, as BrowserUk's original did, while this:
$stats{ scalar( my @r = x() ) }++
produces numbers in the range 1..10 because this time the scalar context is getting the number of items in the array, in contrast to the earlier scalar context which was getting the value of the last element in the list.
For example, a run of this program:
use strict;
use warnings;
use Data::Dumper;
my @array = 0 .. 9;
sub x { return @array[ 0 .. int(rand @array) ] }
my %stats;
$stats{ scalar( my @r = x() ) }++ for 1 .. 1000;
print Dumper( \%stats );
produced:
$VAR1 = {
'6' => 81,
'3' => 110,
'7' => 84,
'9' => 94,
'2' => 96,
'8' => 98,
'4' => 89,
'1' => 123,
'10' => 117,
'5' => 108
Update: For more detail on array vs list context see:
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
use 5.010;
use strict;
sub WA { return wantarray }
my %hash = ('' => 'Hello ', '1' => 'World');
say $hash{ WA() }, @hash{ WA() };
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Are you confusing the element at index 0 with 0 elements- e.g. the empty list? I want to the empty list with equal probability, and my solution does that. I'm just looking for a more succinct way to express it.
| [reply] [Watch: Dir/Any] |
|
Can someone explain why this code produces key values in %stats hash that range "0" to "9"?
The key values, representing the number of elements in the random-length generated arrays should range from "1" to "10", since all generated arrays contain at least one element.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|