0

Help with code to create non-repeating set of 10 numbers

So I'm working on trying to create a non-repeating set to 10 randomly selected numbers between 0 and 9. I have this in a formula field:

let x := [number(void)];
while length(x) < 10 do
        let newItem := [floor(random() * 10)];
        if not contains(x, newItem) then
            x := array(x, newItem)
        end
    end
;
debugValueInfo(x)

 

Thanks to  in this post for helping me get started.

The issues are:

1) if you turn admin on/off to get the formula to trigger, you will notice that is always starts with 0. I don't know why that is. I have another piece of code that doesn't:

let numArray := for loop1 from 1 to 11 do
        floor(random() * 10)
    end;
debugValueInfo(numArray)

 

Even if I remove the if no contains, it always starts with 0. Is the array 'x' not truly empty?

 

2) it does not create a non-repeating set of 10 random numbers. in fact it doesn't seem to do anything except create 10 random numbers that seems to awfully be quite duplicative.

12 replies

null
    • John_Halls
    • 6 mths ago
    • Reported - view

    Hi Fred

    My reply to the previous post gives a non-repeating set of numbers between 0 and 9. It makes an array of 100 numbers but all of them are between 0 and 9. I then use the unique() function to just have a set of 10. It does assume that by the time 100 have been generated we have all 10 numbers, which is almost certain.

    I am trying to create another solution that does a more succinct job.

    Regards John

    • Alain_Fontaine
    • 6 mths ago
    • Reported - view

    let x := slice([0], 0, 0);
    while length(x) < 10 do 
        let newItem := floor(random() * 10);
        if not contains(x, newItem) then
            x := array(x, [newItem])
        end
    end
    ;
    debugValueInfo(x)

      • Fred
      • 6 mths ago
      • Reported - view

      Awesome! That works great.

      Would've never thought to use the slice() command. It still reads to me that there should be a leading zero since you are asking for the first item and zero is that item.

      Now I see that you removed the square brackets from newItem to make the variable a number not an array with a number. Now it makes sense why it was failing. The contains() was breaking because it can't see into the array.

      Then you added the square brackets in the array() command to build the new array.

      • Alain_Fontaine
      • 6 mths ago
      • Reported - view

        According to the definition of the "slice" function, "slice(array,0,0)" produces a slice that starts with the first element, and ends BEFORE the first element, which means an empty array. It’s a way to produce an empty array with elements whose type is defined. If someone has a better idea…

      The "hit or miss" approach of the above procedure has the inconvenient that the (pseudo-)random number generator is often run more than once before actually accepting a number. Depending on the actual implementation of the (pseudo-)random number generator, this could lead to a less than perfect randomness. It is possible to run the generator once per generated number:

      let inputArray := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      debugValueInfo(for i in range(length(inputArray), 0) do
                  let n := floor(random() * i);
                  let e := item(inputArray, n);
                  inputArray := array(slice(inputArray, 0, n), slice(inputArray, n + 1, i));
                  e
              end)
      

      The elements of "inputArray" can of course be of any type, so this is a generic array shuffler.

      • Fred
      • 6 mths ago
      • Reported - view
       said:
      According to the definition of the "slice" function, "slice(array,0,0)" produces a slice that starts with the first element, and ends BEFORE the first element, which means an empty array.

       Thanks for the clarification. I was thinking along that line last night as I was falling asleep. I remembered that slice is not inclusive of the last number in the range, so we get what you wrote.

    • red_kite
    • 6 mths ago
    • Reported - view

    Or an other way

    let r := range(0, 10);
    for i in range(10) do
        let result := item(r, random() * cnt(r));
        r := r[!= result];
        result
    end
    
      • John_Halls
      • 6 mths ago
      • Reported - view

       Ah, that's what I was trying to put together. It would have taken me days to put it so succinctly.

      • red_kite
      • 6 mths ago
      • Reported - view

       The concentrate from the knowledge of everyone here and my joy in optimizations

    • Fred
    • 6 mths ago
    • Reported - view

    So happy to see all of the different ways any solution can be done. You guys are the best.

      • John_Halls
      • 6 mths ago
      • Reported - view

       Hi Fred, so good to see these techniques unfold. I have NEVER used range() before. It's such a powerful function. Unlike the for i from 0 to 10 do statement range() allows for descending numbers, and stepped numbers, 0,2,4,6,8 etc.

      Great stuff. 

      Footie tonight, for any of you Brits out there!

      • Fred
      • 6 mths ago
      • Reported - view

      This was my first attempt at using the while function. The while scares me.

      • Alain_Fontaine
      • 6 mths ago
      • Reported - view

       Righty so… It is the easiest way known to humanity  to produce infinite loops 🌪.

Content aside

  • Status Answered
  • 6 mths agoLast active
  • 12Replies
  • 73Views
  • 4 Following