extract a random number of items from an array

J

Josselin

given an array of values, how should I extract an random number of these values

a = [13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106]

def extract_values( an_array, n)
...
return another_array of n values extracted randomly from an_array
end

I don't know where to start ..
- create an array of n random indexes from 0 to an_array.length, and
use it to extract the value

tfyh

joss
 
J

James Edward Gray II

given an array of values, how should I extract an random number of
these values

a = [13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30,
31, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92,
93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106]

Just give a random chance that a value is added to the result set:
=> [13, 15, 23, 24, 25, 26, 27, 28, 29, 31, 41, 42, 44, 45, 46, 47,
49, 51, 52, 53, 55, 58, 60, 61, 62, 66, 67, 68, 69, 70, 71, 72, 73,
75, 76, 78, 81, 82, 83, 89, 90, 91, 94, 95, 98, 99, 100, 101, 103,
104, 105, 106]=> [13, 18, 19, 20, 21, 24, 26, 27, 28, 29, 30, 31, 41, 42, 44, 48,
49, 51, 52, 53, 55, 57, 58, 59, 62, 63, 64, 66, 68, 70, 79, 81, 82,
83, 86, 89, 90, 91, 92, 94, 97, 98, 102, 104, 105, 106]=> [15, 17, 18, 19, 20, 21, 23, 25, 30, 41, 44, 45, 46, 49, 50, 51,
52, 53, 54, 57, 59, 63, 64, 66, 68, 70, 72, 73, 76, 78, 79, 81, 82,
90, 91, 95, 97, 101, 102, 104]

Hope that helps.

James Edward Gray II
 
J

Josselin

given an array of values, how should I extract an random number of
these values

a = [13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93,
94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106]

Just give a random chance that a value is added to the result set:
=> [13, 15, 23, 24, 25, 26, 27, 28, 29, 31, 41, 42, 44, 45, 46, 47,
49, 51, 52, 53, 55, 58, 60, 61, 62, 66, 67, 68, 69, 70, 71, 72, 73,
75, 76, 78, 81, 82, 83, 89, 90, 91, 94, 95, 98, 99, 100, 101, 103,
104, 105, 106]=> [13, 18, 19, 20, 21, 24, 26, 27, 28, 29, 30, 31, 41, 42, 44, 48,
49, 51, 52, 53, 55, 57, 58, 59, 62, 63, 64, 66, 68, 70, 79, 81, 82,
83, 86, 89, 90, 91, 92, 94, 97, 98, 102, 104, 105, 106]=> [15, 17, 18, 19, 20, 21, 23, 25, 30, 41, 44, 45, 46, 49, 50, 51,
52, 53, 54, 57, 59, 63, 64, 66, 68, 70, 72, 73, 76, 78, 79, 81, 82,
90, 91, 95, 97, 101, 102, 104]

Hope that helps.

James Edward Gray II

thanks James that's exactly what I need
I made various tests like a.select { rand(10).zero? }
and I got different results.. as I want

I try to understand the logic behind your solution (not to dry stupid...)

select from array a ... { for each item. 0#no 1#yes } ok for
rand(2) , if I use rand(10) less chances to get it
is that right ?
 
J

James Edward Gray II

given an array of values, how should I extract an random number
of these values
a = [13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30,
31, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106]
Just give a random chance that a value is added to the result set:
a.select { rand(2).zero? }
=> [13, 15, 23, 24, 25, 26, 27, 28, 29, 31, 41, 42, 44, 45, 46,
47, 49, 51, 52, 53, 55, 58, 60, 61, 62, 66, 67, 68, 69, 70, 71,
72, 73, 75, 76, 78, 81, 82, 83, 89, 90, 91, 94, 95, 98, 99, 100,
101, 103, 104, 105, 106]
a.select { rand(2).zero? }
=> [13, 18, 19, 20, 21, 24, 26, 27, 28, 29, 30, 31, 41, 42, 44,
48, 49, 51, 52, 53, 55, 57, 58, 59, 62, 63, 64, 66, 68, 70, 79,
81, 82, 83, 86, 89, 90, 91, 92, 94, 97, 98, 102, 104, 105, 106]
a.select { rand(2).zero? }
=> [15, 17, 18, 19, 20, 21, 23, 25, 30, 41, 44, 45, 46, 49, 50,
51, 52, 53, 54, 57, 59, 63, 64, 66, 68, 70, 72, 73, 76, 78, 79,
81, 82, 90, 91, 95, 97, 101, 102, 104]
Hope that helps.
James Edward Gray II

thanks James that's exactly what I need
I made various tests like a.select { rand(10).zero? }
and I got different results.. as I want

I try to understand the logic behind your solution (not to dry
stupid...)

select from array a ... { for each item. 0#no 1#yes } ok for
rand(2) , if I use rand(10) less chances to get it
is that right ?

Exactly. Using rand(10) you would have a 1 in 10 chance that each
number is added the the result set.

James Edward Gray II
 
B

Brian Candler

given an array of values, how should I extract an random number of these
values

a = [13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106]

def extract_values( an_array, n)
...
return another_array of n values extracted randomly from an_array
end

I don't know where to start ..
- create an array of n random indexes from 0 to an_array.length, and
use it to extract the value

Are you trying to do pick 'n' elements from 'a' like lottery balls? i.e.
once a value has been picked once, it cannot be picked again?

Short but inefficient:

result = a.sort_by{rand}[0...n]

More efficient (but deletes elements from 'a', so dup it first if necessary):

result = []
n.times { result << a.slice!( rand(a.size) ) }

Or if I misunderstood the question, and duplicate picks are allowed:

result = []
n.times { result << a[ rand(a.size) ] }

HTH,

Brian.
 
J

Josselin

given an array of values, how should I extract an random number of these
values

a = [13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106]

def extract_values( an_array, n)
...
return another_array of n values extracted randomly from an_array
end

I don't know where to start ..
- create an array of n random indexes from 0 to an_array.length, and
use it to extract the value

Are you trying to do pick 'n' elements from 'a' like lottery balls? i.e.
once a value has been picked once, it cannot be picked again?
no, I need to put all the balls again for the next pick
I am creating a random test set of records , but I'll copy your recipes
in my Ruby notebook... thanks
Short but inefficient:

result = a.sort_by{rand}[0...n]

More efficient (but deletes elements from 'a', so dup it first if necessary):

result = []
n.times { result << a.slice!( rand(a.size) ) }

Or if I misunderstood the question, and duplicate picks are allowed:

result = []
n.times { result << a[ rand(a.size) ] }

HTH,

Brian.
 
B

Brian Candler

no, I need to put all the balls again for the next pick

Still not entirely clear, but I think one of these is what you mean:

Option 1: After picking one ball, you put that one ball back, then pick
another ball, put it back etc. You repeat this 'n' times to get your
selection of 'n' balls.

result = []
n.times { result << a[ rand(a.size) ] }

Clearly this allows for duplicates.

Option 2: You pick 'n' balls out of the bag (without replacement). Then you
put these balls back in, so that on the next run you pick another 'n' balls
from the original set.

b = a.dup
result = []
n.times { result << b.slice!( rand(b.size) ) }

You don't get any duplicates within your selection of 'n' balls, but the
fact that you've picked a ball on one run doesn't prevent it from being
picked on a subsequent run.

Regards,

Brian.
 
J

jzakiya

no, I need to put all the balls again for the next pick

Still not entirely clear, but I think one of these is what you mean:

Option 1: After picking one ball, you put that one ball back, then pick
another ball, put it back etc. You repeat this 'n' times to get your
selection of 'n' balls.

result = []
n.times { result << a[ rand(a.size) ] }

Clearly this allows for duplicates.

Option 2: You pick 'n' balls out of the bag (without replacement). Then you
put these balls back in, so that on the next run you pick another 'n' balls
from the original set.

b = a.dup
result = []
n.times { result << b.slice!( rand(b.size) ) }

You don't get any duplicates within your selection of 'n' balls, but the
fact that you've picked a ball on one run doesn't prevent it from being
picked on a subsequent run.

Regards,

Brian.

But for n > a.size Option 1 fills result with valid values while for
Option 2 it fills it with nil. Problem didn't state that n always <=
a.size.
 
R

Robert Dober

Ooops bad formatting again, sorry for the repost folks:

Actually James' solution does not give you n elements, maybe you want to try this
an_ary.sort_by{ rand }[0..n-1] # Might use a second or two of CPU for
millions of elements though ;)
should do the trick unless you want a *stable* subarray.
Stable means that if x occurs on the LHS of y in an_ary it also does
in your subarray, but if I read you correctly you did not need this.

Cheers
Robert
 
R

Robert Dober

Ooops bad formatting again, sorry for the repost folks:
This seems a mess, I'lll try again

Select randomly and unstably n elements from an array:

ary.sort_by{ rand }[0..n-1] # or [*1..n] if n< ary.size

Select randomly a stable n elements from an array:

ary.values_at( *[*0..ary.size-1].sort_by{ rand }[0..n-1].sort )

Hopefully I got it eventually through in plain text.

Would be nice if someone could confirm even with a harsh "STOP sending
all this crap" ;)

Cheers
Robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top