Shuffling an array randomly

I have an array of CDTs say questions with question structured as:

{

id: 1,

statement: "Text string of question",

options: {List of Options}

}

Like multiple values like the above.

I would like to shuffle this array of questions randomly so that every time I print this array the questions are in no particular order and are different from last time. Example if I pick the array first time it had an order:

1, 4, 2, 5, 3

But next time I pick same array it should be ordered randomly like:

3, 5, 1, 4, 2

Also is there any possible way to implement Rand() ordering in the query like we do in SQL?

  Discussion posts and replies are publicly visible

  • +1
    Certified Lead Developer

    There are various ways to do this, but anything you do you'll have to build yourself.

    A quick-and-dirty way I just thought of:

    1. use a!forEach to loop over the CDT array and use updateDictionary() to add a new ad-hoc property to each one, i.e. "order", set to the value of a rand() call.  This will give a random decimal between 0 and 1 to all items; they should almost always be unique as far as I know.
    2. Sort the array based on the "order" decimal (use the "toDataSubseet" trick to sort an array of dictionary based on the value of a property).
  • This will give you the numbers 1..5 in a random order, which could be used as an index for the CDT array.

    a!localVariables(
      local!array: floor(rand(50)*5)+1,
      union(local!array, local!array)
    )

  • 0
    Certified Lead Developer
    in reply to normanc

    I like it - though it should be noted that this could occasionally (probably very rarely) return only 4 results if none of the 50 "coin flips" come up for one of the 5 numbers.  I assume if you push the "random array length" value high enough you'll eventually get zero failures, though i'm not sure what that'll do to the efficiency of the rule.

    I just tested and this happened 3 out of 10,000 times (though on some other runs of the same code it happened 0 times):

    a!flatten(
      a!forEach(
        enumerate(10000), /* number of times to test */
      
        a!localVariables(
          local!length: 5,
          local!array: floor(rand(local!length*10) * local!length) + 1,
          if(
            length(union(local!array, local!array)) < local!length,
            "flag",
            {}
          )
        )
      )
    )

  • Thanks Mike,

    This was a really innovative way to sort and shuffle a large array at low perofromance cost. But I feel that since we have the functionality of fetching randomly sorted records direct from SQL query in MySQL, Appian should incorporate a way to use that functionality as it will save a great coding time and performance load will be reduced.

  • 0
    Certified Lead Developer
    in reply to adityaamba

    Something like that would need to be built into the a!queryEntity function or one of its components - you could always file a feature request ticket with Appian Support, however I wouldn't expect it to be prioritized anytime soon without a strong use case on your end.

    Out of boredom I went ahead and implemented a standalone function where you input the desired number of items and it returns a randomized list of integer indices 1...N, where we're guaranteed to have no duplicates or missing numbers.  This integer array could then be used to index into any particular array in a randomized manner.

    a!localVariables(
      
      local!targetSize: 25,
      
      local!dict: a!forEach(
        enumerate(local!targetSize),
        
        a!map(
          integer: fv!index,
          sort: rand()
        )
      ),
      
      local!sorted: todatasubset(
        local!dict,
        a!pagingInfo(
          startIndex: 1, batchSize: -1,
          sort: a!sortInfo(field: "sort", ascending: true())
        )
      ),
      
      local!sorted.data.integer
    )