Extract a random number of items from an array

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

On Feb 25, 2007, at 10:20 AM, Josselin wrote:

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 G. II

Here is my solution, it should be work.


def extract_values(array, n)
len = array.length
(len - 1).downto(len - n) do |i|
sway_index = rand(len) % i
array[i], array[sway_index] = array[sway_index], array[i]
end

return array[len-n..len-1]

end

On Feb 25, 2007, at 11:15 AM, Josselin wrote:

90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
81, 82, 83, 86, 89, 90, 91, 92, 94, 97, 98, 102, 104, 105, 106]

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 G. II

On 2007-02-25 17:41:58 +0100, James Edward G. II
[email protected] said:

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 G. 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 ?

On Mon, Feb 26, 2007 at 01:20:07AM +0900, Josselin wrote:


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.

If you use this way, then how we you get exactly n values randomly from
the
given array?

I doubt the correct of this way.

My solution should meet your requirement. :slight_smile:

On 2007-02-25 21:08:35 +0100, Brian C. [email protected] said:

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

On Mon, Feb 26, 2007 at 06:40:05AM +0900, Josselin wrote:

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

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.

On 2/25/07, Mingquan C. [email protected] wrote:

58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,

a.select { rand(2).zero? }
James Edward G. II
is that right ?

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 :wink:
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

On Feb 25, 4:50 pm, Brian C. [email protected] wrote:

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.

Ooops bad formatting again, sorry for the repost folks:

On 2/26/07, Robert D. [email protected] wrote:

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 :wink:
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

On 2/26/07, Robert D. [email protected] wrote:

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” :wink:

Cheers
Robert