How to extract some random values from data set?

Let’s say I have array of int, (0,1,2,3,13).

If I want to extract random value from above one, this is easy by using Random.Range,

but what if I want to extract random many values from above, but those should not be duplicated?

for example, I want to extract 4 values (like 3,6,8,9) from above randomly, is there a easy way for it?

using [for] ? or Linq? or?

Thanks.

google for shuffle bag. basically you need to remove the choosen entries so that they cannot be picked again in this run (keep them in separate collection if you refill the dataset later).

I would do something like this based on my blog post http://mrmoss.net/2013/cunity3d-shuffling-an-array/

    private int[] numbers = new int[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    private int[] Shuffle(int[] obj, int count)
    {
        if (obj.Length < count)
        {
            Debug.Log("Tried to get more numbers than in array");
            return null;
        }

        int[] tmpObj = obj;
        int[] returnedObj = new int[count];
        for (int i = 0; i < count; i++)
        {
            int temp = tmpObj[i];
            int objIndex = Random.Range(0, tmpObj.Length);
            tmpObj[i] = tmpObj[objIndex];
            returnedObj[i] = temp;
        }
        return returnedObj;
    }

    private void PrintRandomNumbers()
    {
        int[] shuffled = Shuffle(numbers, 5); //Get a shuffled array of numbers, max of 5!
        for (int i = 0; i < shuffled.Length; i++)
        {
            Debug.Log(i);
        }
    }

Thanks for share. This code just returns all shuffled 10 size values. I want to get some specific sized value. (if 5 random values, something like 3,6,7,8,9).

    void Start(){
        //The array of numbers we can pick from
        int[] available = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13};
        
        //Pick 5 from choices
        int[] pickedFromChoices = PickRandomUniqueIntegers(available, 5);
        
        //Log results: all are unique
        foreach(int result in pickedFromChoices)
            Debug.Log (result);
    }
    
    //Returns an array of "number" integers out of "choices."
    //All choices are unique elements, unless "choices" contains duplicates.
    int[] PickRandomUniqueIntegers(int[] possible, int number){
        
       //A safety check. Prevents us from going out of bounds if the array of choices is too small and such.
       if(possible.Length == 0 || number > possible.Length || number < 1){
          Debug.Log("The operation could not be completed.");
          return new int[0];
       }
        
       //We copy the array so that we don't end up swapping elements in the original we were handed
       int[] choices = new int[possible.Length];
       System.Array.Copy(possible, choices, possible.Length);
        
       //The array to return once we are done picking integers
       int[] picked = new int[number];
        
        //For as many numbers are requested, grab a random number, place it in the new array.
        //We swap the chosen number with the last one in the array and shorten our random range
        //by one each iteration so that no element can be chosen twice.
        for(int i = 1; i <= number; i++){
            int index = Random.Range(0, choices.Length - i);
            int choice = choices[index];
            choices[index] = choices[choices.Length - i];
            choices[choices.Length - i] = choice;
            picked[i - 1] = choice;
        }

        return picked;
    }

Here’s some code you can use that I just wrote. Just pass the function PickRandomUniqueIntegers() any array of integers along with the number of unique elements you want. It loops through the array and grabs a random element, placing it into an array to return to you. It does not choose an element more than twice because it swaps the chosen element with the last element in the array, and we ignore one more element of the array at the end every iteration. In example, on the first loop we grab any number and swap it to the end. On the next loop, we grab any number before the one on the end and swap it to the position one before the end. On the loop after that, we grab any number before the two on the end and swap it to the position two from the end, and so on.

It would make more sense to shuffle the values then take the first (n) values

That’s another approach I didn’t really think of. I don’t think it would be any more efficient, though. In fact, depending on how you shuffled the array and the size of the array it could be much slower. If you have an array of 1000 items and want a random unique five, this would require exactly five swaps. No matter the size of the array, the amount of swaps required is the same. Shuffling it first to create an even distribution of permutations would take more than five swaps, right? Thoughts?

There are numerous methods to choose from, each with its own benefits/downsides… I have another method that I used once which again was different, but no efficient if you wanted to use a large source array. As for performance in the scenario you mention… you’re probably correct, although its one of those things that would most likely be negligible.

Agreed. I’d say there are benefits to most approaches to these sorts of problems. One is performance, while the other is how natural the approach to the problem seems and how easy it is to understand. Natural code leads to natural understanding, which makes it easier to maintain. However, for basic code like this that can be reused in any number of situations, I usually try to get code that scales the least, performance wise, with the size of the set of data I’m working on.

Of course, in the case of a large array, the code above would take longer in copying the original array than actually selecting elements from it. I guess the fastest approach in that case would be to not alter the original array and thus not require copying it. For example, storing the indexes of elements you’ve already used and picking another if you land on one, removing the need to shuffle elements around. The performance implications there are reliant on the ratio between array size and the number of elements you need. As the array size goes up and the number of elements requested becomes smaller in comparison, it actually gets faster on average since you’re more likely to get a unique index and as such will spend less time trying again. This just flips the problem, though, since it would get slower and even potentially loop forever if the requested amount of elements was too large in comparison to the array.

Sorry if I’m rambling; I’m feeling a little ill. :stuck_out_tongue:

I amended my original post

Here is my solution.

 ArrayList engArr = new ArrayList();
ArrayList pickedNum = new ArrayList();

//// insert 14 string datas to engArr.... 

void Pickup(){
        int num = 5;  
            while(0 < num){
                int index = Random.Range(0, engArr.Count);
                string ranStr = (string)(engArr[index]);
                for(int b = 0 ; b < engBank.Length ; b++){   // engBank has same 14 strings with engArr
                    if(ranStr == engBank[b]){
                        pickedNum.Add(b);
                    }
                }
                engArr.Remove(ranStr);
                engArr.TrimToSize();
                strData[num-1] = ranStr;                    // insert random picked string to another array[] you will actually use this
                num--;
            }