Random Number snippet

Hi folks

Anyone have a snippet of code to generate a list of numbers from 1 to x so that the numbers are in random order and do not repeat?

For example: Random list from 1 to 10

{2, 5, 7, 8, 1, 3, 6, 4, 10, 9}

Thanks

Is this what you mean?

Jon


[This script was automatically tagged for color coded syntax by Convert Script to Markup Code]

Not bad, jonn, except that your script will take exponentially longer the more numbers there are in the list because there’s a larger number of double hits that have to be taken into account.

A much faster solution (although it’s more script code) would be to eliminate each item from the list as its picked. That way you know any number in the original list is still unique and you don’t need to scan the random list to see if you’ve already chosen it.

Something like this:


[This script was automatically tagged for color coded syntax by Convert Script to Markup Code]

Note that I’ve set this up to accept a low and high mark as parameters to the handler. This makes is very flexible, but isn’t necessary if you know you’re dealing with the same set of numbers.

That’s good! :slight_smile: Like Jon’s script, it assumes that the number range is not greater than the number of numbers required, but it’s easily adapted if not.

An even more efficacious speed hike with big lists is to write your own random number generator rather than relying on ‘random number’ (each use of which is an OSAX call). In conjuction with an optimisation of Camelot’s handler, it might look like this:

property fastRandomSeed : pi 

on reseedFastRandom()
  set fastRandomSeed to (fastRandom from 0.0 to (current date)'s time) mod 1
end reseedFastRandom

on fastRandom from a to b
  set fastRandomSeed to (fastRandomSeed * pi) mod 1
  if a's class is integer and b's class is integer then
    if a < b then
      a + (b - a + 1) * fastRandomSeed div 1
    else
      a + (b - a - 1) * fastRandomSeed div 1
    end if
  else
    a + (b - a) * fastRandomSeed
  end if
end fastRandom

on getRandomList(low, high)
  local randomList, pick
  script o
    property numList : {}
    property randomList : {}
  end script
  
  reseedFastRandom()
  repeat with i from low to high
    set end of o's numList to i
  end repeat
  
  repeat high - 1 times
    set pick to fastRandom from 1 to high
    set end of o's randomList to item pick of o's numList
    set item pick of o's numList to missing value
    set o's numList to o's numList's numbers
    set high to high - 1
  end repeat
  set end of o's randomList to beginning of o's numList
  return o's randomList
end getRandomList

getRandomList(1,100)

Sorry. I forgot to allow for non-1 values of ‘low’. It’s only one extra line, but here’s the whole thing again to avoid confusion:

property fastRandomSeed : pi

on reseedFastRandom()
  set fastRandomSeed to (fastRandom from 0.0 to (current date)'s time) mod 1
end reseedFastRandom

on fastRandom from a to b
  set fastRandomSeed to (fastRandomSeed * pi) mod 1
  if a's class is integer and b's class is integer then
    if a < b then
      a + (b - a + 1) * fastRandomSeed div 1
    else
      a + (b - a - 1) * fastRandomSeed div 1
    end if
  else
    a + (b - a) * fastRandomSeed
  end if
end fastRandom

on getRandomList(low, high)
  script o
    property numList : {}
    property randomList : {}
  end script
  
  reseedFastRandom()
  repeat with i from low to high
    set end of o's numList to i
  end repeat
  
  set high to high - low + 1
  repeat high - 1 times
    set pick to fastRandom from 1 to high
    set end of o's randomList to item pick of o's numList
    set item pick of o's numList to missing value
    set o's numList to o's numList's numbers
    set high to high - 1
  end repeat
  set end of o's randomList to beginning of o's numList
  return o's randomList
end getRandomList

getRandomList(1, 100)

Create an ordered list of numbers, then randomise the order. Very efficient.

Using the List library from AppleMods http://applemods.sourceforge.net:

property _Loader : run application "LoaderServer"

----------------------------------------------------------------------
-- DEPENDENCIES

property _List : missing value

on __load__(loader)
	set _List to loader's loadLib("List")
end __load__

----------------------------------------------------------------------

__load__(_Loader's makeLoader())

on orderedList(fromNum, toNum, byStep)
	set lst to {}
	repeat with i from fromNum to toNum by byStep
		set lst's end to i
	end repeat
	return lst
end orderedList

_List's unsortList(orderedList(1, 100, 1))

Gosh yes. After reading your post, I wrote a random-swap routine that turned out to be about three times as fast as what I posted earlier. Then I downloaded your list library and had a look at the ‘unsortList’ handler. It’s very similar code, but your built-in, specialised random integer generator makes it about a quarter as fast again. (Tested with a 1000-item list, not in a library context.)

That’s a pretty mean list randomiser.