ensuring random list of numbers are unique

Hey all, using ruby 1.8.7, I wrote this:

500.times.map { Integer((rand * 1) * 1000) / Float(1000) }

Basically, this gives me a list of 500 random decimal numbers that are rounded to 3 places. However, I also want to make sure that all are unique.

thanks for response

500.times.map { Integer((rand * 1) * 1000) / Float(1000) }

Basically, this gives me a list of 500 random decimal numbers that are rounded to 3 places. However, I also want to make sure that all are unique.

Tack a .uniq to the end...

-philip

Here is one thing that comes to mind

a = (1..1000).to_a a.shuffle!

pick 1st 500 a[0,500]

last 500 item from the list a[-500..-1]

If you want you can call shuffle a few times, see what works best for you.

Hey all, using ruby 1.8.7, I wrote this:

500.times.map { Integer((rand * 1) * 1000) / Float(1000) }

Basically, this gives me a list of 500 random decimal numbers that are rounded to 3 places. However, I also want to make sure that all are unique.

.uniq() doesn't guarentee 500 number exactly. .shuffle() just tosses the collection and doesn't give you unique numbers.

You'd better to implement method:

def secure(number, precision)   collection =   collection |= [SecureRandom.random_number.round(precision)] while collection.size < number   collection end

secure(500, 3)

=> collection of 500 unique random numbers.

Sweet!

Valery Kvon wrote in post #1049372:

You'd better to implement method:

def secure(number, precision)   collection =   collection |= [SecureRandom.random_number.round(precision)] while collection.size < number   collection end

secure(500, 3)

=> collection of 500 unique random numbers.

One simple way to get what you want is by using a set:

Here's your method of generating random numbers. Don't count on it giving you "secure" random numbers, but this technique won't care how you produced them.

#!/usr/bin/env ruby require 'set'

def random_numbers(n = 500)   my_set = Set.new   while my_set.size < 500     value = Integer((rand * 1) * 1000) / Float(1000)     my_set << value   end   my_set.to_a end

puts random_numbers.size

Robert Walker wrote in post #1049376:

#!/usr/bin/env ruby require 'set'

def random_numbers(n = 500)   my_set = Set.new   while my_set.size < 500     value = Integer((rand * 1) * 1000) / Float(1000)     my_set << value   end   my_set.to_a end

puts random_numbers.size

One caveat with this technique: Make sure you build in some "circuit breaker" protection code. The more numbers you ask this to generate the more rounds it will take to produce the result. Generating 500 unique numbers is averaging about 700 rounds. The closer to 1000 you get the more rounds it will take. Over 1000 and it will never finish.

This is a classic "how do I achieve my solution?", rather than a "here's my problem... how can I solve it" post...

Can we back up a second please? What are you trying to achieve with this list of 500 numbers? And what do you want to do if the list you have generated does contain duplicates? As already said, you can use the .uniq method to remove dupes - but that might leave you with an array of 496 elements... would that be a problem? Are you really asking "how do I generate an array of 500 random numbers"?

What do you want to do with these 500 random numbers? Considering that one user could make a request and get their 500 randoms, and another user could do the same - there could be duplicates across users. Is this going to be a problem?

Please try to ask clearer questions, as the way it stands, I could spend ages of my time coming up with solutions to what I *think* is your problem, just to have you say "nope... that's not what I was after". Multiply that across the subscribers to this list, and you've wasted a hell of a lot of peoples' time around the world :-/

PS BTW Why are you multiplying by 1 in your example code? (and does that line even work if you paste it into your console, as it explodes for me with a LocalJumpError... but that may just be Ruby versions...)

Robert Walker wrote in post #1049376:

#!/usr/bin/env ruby

require ‘set’

def random_numbers(n = 500)

my_set = Set.new

while my_set.size < 500

value = Integer((rand * 1) * 1000) / Float(1000)
my_set << value

end

my_set.to_a

end

puts random_numbers.size

One caveat with this technique: Make sure you build in some "circuit

breaker" protection code. The more numbers you ask this to generate the

more rounds it will take to produce the result. Generating 500 unique

numbers is averaging about 700 rounds. The closer to 1000 you get the

more rounds it will take. Over 1000 and it will never finish.

Another caveat is that the Array contains “Float” objects, while the original question was “500 unique decimals”. Two issues here:

  1. if “decimals” are asked in the problem statement, why then do we serve Floats in the result?

  2. The problem is that for uniqueness, we need the ‘==’ operator and on Floats that represent fractional numbers in the decimal system,

equality is not a stable function (as was discussed many times before …).

So, in all proposed solutions, I would exchange this line:

value = Integer((rand * 1) * 1000) / Float(1000)

with this one:

  value = rand(1000) / BigDecimal.new(1000)

HTH,

Peter

thanks for responses, the ultimate goal was just to ensure a list of 500 (no more or less) unique random decimals that are 3 places which would be generated only one time. Currently Im storing them as a float in the mysql database.

One time for ever? You do realise there's only 1000 numbers between 0 and 0.999? After two runs, you'll have used up the whole pool.

Do yourself a favor and change your migration with a line like this:

t.decimal :number, :precision => 10, :scale => 3

That’s all it takes to use decimals (with 3 digits following the decimal point)

in the database too.

HTH,

Peter