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

http://ruby-doc.org/core-1.9.3/Array.html#method-i-uniq

-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