Skip to main content
February 24, 2023
Question

Generate RANDOM and UNIQUE numbers for a specific range

  • February 24, 2023
  • 10 replies
  • 0 views

Hello,

I am trying to randomly sample x amount of rows from a CDT by generating x random numbers in the range 1:length(myCdt). The issue I am getting is that some of these random numbers are repeated. 

Is there a way to generate random numbers  in a given interval and have them be unique? 

Here is what I have so far:

local!randomNumbers:if(

length(local!query)>15,
1+ tointeger(rand(15) * length(local!query)),
local!query,

),

    10 replies

    gayathris111098
    February 24, 2023
    stefanhelzle0001
    Brainy
    February 24, 2023

    Without using a recursive approach, this is tricky. The most simple approach might be, to just generate more numbers, get the unique ones and then take the first few. Find a code example below.

    index(
      union(tointeger(rand(100)*50), tointeger({})),
      enumerate(15) + 1,
      {}
    )

    February 24, 2023

    I see, is there a limit to how high that number should be?

    stefanhelzle0001
    Brainy
    February 24, 2023

    Hm... as this is random, it could, in theory, generate a thousand times the same number. In practice, you could double it.

    In my tests, when generating 50 numbers, I had 0-3 double. When you need 15, you should be good with 20. If your application breaks, in case you only show 13 or 14 items, go a bit higher.

    adityag9712
    February 24, 2023

    a!localVariable(
    
    local!possibleNumbers: difference(
    1+enumerate(ri!upper),
    1 + enumerate(ri!lower)
    ),
    
    local!count: length(local!possibleNumbers),
    
    local!randomIndex: tointeger(local!count*(rand())),
    
    if(local!randomIndex =0,
    local!possibleNumbers[tointeger(local!count*(rand()))],
    
    local!possibleNumbers[local!randomIndex]
    )
    
    )

    stefanhelzle0001
    Brainy
    February 24, 2023

    Your code generates a single random number between two boundaries. A more simple variant is

    ri!lower + tointeger(rand() * (ri!upper - ri!lower))

    peter.lewis
    Employee
    February 24, 2023

    There might be a simpler way to do this, but this solution should guarantee a random order without repeated data regardless of how many values you have:

    a!localVariables(
      local!numberOfValues: 15,
      local!randomData: rand(local!numberOfValues),
      local!index: a!forEach(
        items: local!randomData,
        expression: rank(
          fv!item,
          local!randomData
        )
      ),
      index(
        enumerate(local!numberOfValues)+1,
        local!index
      )
    )

    Basically you just generate a list of random decimals and then find the rank in the list of each of them. That will guarantee that all values are used and that they don't repeat!

    amans0009
    February 25, 2023

    here is the recursive approach for getting x amount of unique numbers between a define range

    a!localVariables(
      local!random: ri!min + tointeger(rand() * (ri!max - ri!min)),
      local!arrray: append(ri!array, local!random),
      if(
        length(union(local!arrray, local!arrray)) >= ri!count,
        local!arrray,
        rule!CP_getRandomList(
          min: ri!min,
          max: ri!max,
          count: ri!count,
          array: union(local!arrray, local!arrray)
        )
      )
    )
    // NOTE - count < max - min    
    ,

    more insights ->