# How to get 5 random/unique values from an array



## andrewsf (Dec 5, 2019)

I am struggling with finding an approach to grabbing unique values from an array. I have an array of items and I want to randomly grab 5 values without any duplicates. Any help would be great. Thanks.


----------



## David Cuny (Dec 5, 2019)

Apologies for the pseudo-language. It assumes a 1-based array.

Entirely untested, of course. 

The routine picks values from the array *myArray*, and stores them into the array *pickedValue[].*

It then replaces the value at the picked location with a value from the end of the array, and shortens the array length by one.

Once it's done, it uses *pickedIndex[]* to restore values back to their original locations. 


```
// number of values to choose
var numPicks = 5

// hold the picked values and their locations
var pickedValue[numPicks]
var pickedIndex[numPicks]

// size of array
var arraySize = myArray.length()

// pick the values
for (i = 1, i <= numPicks; i++) {
    // choose a random location in the array
    var index = math.random( arraySize )

    // get the value and location
    pickedValue[i] = myArray[index]
    pickedIndex[i] = index

    // replace the picked value with one from the end of the array
    myArray[index] = myArray[arraySize]

    // decrease the size of the array
    arraySize -= 1
}


// restore the values to myArray
for (i = 1, i <= numPicks; i++) {
    myArray[pickedIndex[i]] = pickedValue[i]
}
```


----------



## azrulsaleh (Dec 7, 2019)

andrewsf said:


> I am struggling with finding an approach to grabbing unique values from an array. I have an array of items and I want to randomly grab 5 values without any duplicates. Any help would be great. Thanks.



There's many ways to do this. To confirm before giving another suggestion, are you looking to have random unique numbers between 2 back to back values? Or 5 unique values in a row before looping through the array again?


----------



## andrewsf (Dec 7, 2019)

Hi,
Yes, let me be a bit more clear. I basically have 5 dropdown menus that I want to make a random selection in each with none duplicating the others. There are many ways to do this in say Javascript but I'm struggling with translating it to KSP. Below is a quick example of one way I might do it in Javascript. Of course there are much simpler ways to do it in Javascript but I'm trying to be abstract. If someone could give me a hand translating this to KSP. I am using Nils Liberg's Editor in Sublime if that helps. Thanks so much for your help!

var patches = ["Patch 0", "Patch 1", "Patch 2", "Patch 3", "Patch 4", "Patch 5", "Patch 6", "Patch 7", "Patch 8", "Patch 9", "Patch 10"];
var randomPatches = [];

function getRandomPatches() {
randomPatches = [];
for(var i = 0; i < 5; i++) {
getRandomPatch();
}
console.log(randomPatches);
}

function getRandomPatch() {
var isValid = false;
var randomPatchIndex = null;
while(isValid == false) {
randomPatchIndex = Math.floor((Math.random() * patches.length));
if(validateRandomPatch(randomPatchIndex) == true) {
randomPatches.push(patches[randomPatchIndex]);
isValid = true;
}
}

}

function validateRandomPatch(index) {
for(var i = 0; i < randomPatches.length; i++) {
if(randomPatches_ == patches[index]) {
return false;
}
}
return true;
}

getRandomPatches();_


----------



## Patrik Herman (Dec 7, 2019)

andrewsf said:


> if(randomPatches == patches[index]) {



Here I think you should use `randomPatches[i]` instead, else you will get duplicate values which indexes are > 0 (because in JavaScript, [value] == value, but [value,value2] != value).

*Regarding the Kontakt solution, here are a couple of notes:*
- Kontakt has two types of arrays, int and string arrays (also real arrays, but they are irrelevant here right now)
- you can not use JavaScript's .pop() or .push() commands, you have to predefine an array with an initial size and use a separate variable to define its length
- string comparisons are non-existent in Kontakt
- I'm using SublimeKSP (check out this link for more information) for a cleaner way to show the solution and better understanding for a JS programmer
- list type of array from SublimeKSP can not be used in this scenario because the code is executed on a click of a button, not in "on init" callback - you can check out this link for more information
- I'm using NULL as a constant value of -9999 just for the code to look slightly nicer and more understandable.

*Now onto my solution:*
- The idea is to set up 3 arrays: patches (with a list of patches), random_patches (where values get picked to) and temp_array_of_ids (where null values are inserted for the script to know which patch names to NOT pick and therefore to make the selection unique)
- Next, a random index needs to be picked. We can do that using while() where we check if temp_array_of_ids has a "free spot" (not NULL)
- Then, patches[random_position] is our unique element that gets pushed to our new array. The workaround (because KSP) is to increase imaginary array's size using a variable
- Next, temp_array_of_ids[random_position] gets set to NULL because we want this value to not get picked.
- Run that n times (in your case it's 5) and voilà, you've got yourself an array with uniquely picked values!

I want you to try that yourself first, though! I can promise you will learn a lot by trying it out without any code help first. If you are stuck, you can check the spoiler (written in SublimeKSP, so you will, of course, need to compile it first):


Spoiler: Solution





```
on init
    make_perfview
    declare i
    declare const NULL := -9999
    declare ui_switch trigger
    declare ui_label debug(2,5)

    declare !patches[11] := ("Patch 0", "Patch 1", "Patch 2", "Patch 3", "Patch 4", "Patch 5", "Patch 6", "Patch 7", "Patch 8", "Patch 9", "Patch 10")
    declare const patches_size := 11
    declare !random_patches[patches_size] := ("")

    message("")
end on

function string_array_get_unique_set(array_from, array_to, number_of_patches)
    declare random_position
    declare temp_array_of_ids[patches_size]
    declare array_to_counter := 0

    /*
        RESET ARRAYS
    */
        for i := 0 to patches_size-1
            temp_array_of_ids[i] := 0
        end for
        for i := 0 to number_of_patches-1
            array_to[i] := ""
        end for

    for i := 0 to number_of_patches-1
        /*
            GENERATE random position
        */
            random_position := random(0, patches_size-1)
            while (temp_array_of_ids[random_position] = NULL)
                random_position := random(0, patches_size-1)
            end while

        // These two lines work as .push() in JavaScript
            array_to[array_to_counter] := array_from[random_position]
            inc(array_to_counter)

        // A NULL value will be set at the patch name's position to later not choose this value again
            temp_array_of_ids[random_position] := NULL
    end for
end function

on ui_control(trigger)
    trigger := 0

    // one-liner - how simple, right? hehe :P
    string_array_get_unique_set(patches, random_patches, 5)

    // display all of the random generated patches names
    set_text(debug, "")
    for i := 0 to 4
        add_text_line(debug, random_patches[i])
    end for
end on
```





Good luck!

Patrik


----------



## andrewsf (Dec 9, 2019)

Patrik,
Yes, I actually do have randomPatches_ in my code. I must have copied it over before I caught that bug. I actually just realized where the bug in my original code was (super simple fix) and now it works like a charm. Thank you for your help._


----------

