How can I make so that my Values dont repeat with Random.Range()?

So to explane it a little bit better, I made a little script that spawns (instanciates) some gameObjects at randomly generated positions. I made it so my z cordinates are randomly generated from 20 to 100 with steps of 10, and x cordinate that can only be 2.2f or -2.2f (but that is not the problem) and everything is done 6 times when function is called. At the end I get (one example) for z cordinates: 30, 30, 60, 50, 40, 60, and repeating values are the problem. How can I make so that no values repeat? Here is my code…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnerScript : MonoBehaviour
{
    public GameObject GateSingle;
    public GameObject GateDouble;
    public static SpawnerScript instance;

    float RandomXValue;

    float minZValue = 20;
    float maxZValue = 100;
    float StepZSize = 10;

    void Awake()
    {
        instance = this;
    }

    public void Spawn()
    {
        for (int i = 0; i < 6; i++)
        {
            float randomZ = Random.Range(minZValue, maxZValue);
            float numSteps = Mathf.Floor(randomZ / StepZSize);
            float newRandomZ = numSteps * StepZSize;

            int RandomXCheck = Random.Range(0, 2);

            if (RandomXCheck == 0)
            {
                RandomXValue = -2.2f;
            }
            else if (RandomXCheck == 1)
            {
                RandomXValue = 2.2f;
            }

            Instantiate(GateSingle, new Vector3(RandomXValue, 0, newRandomZ), Quaternion.identity);
        }
    }
}

Hi! I can think of two ways to solve this problem:
→ Option 1 (the one I recommend you for this case)
Declare a list for the available (not used) z values (availableZValues). Fill the first list with a for loop and, then, create another for loop that takes values from that list and removes them from it:

public void Spawn()
    {
        List<float> availableZValues = new List<float>();

        for (int i = minZValue; i < maxZValue; i += StepZSize) //Here, if you write <=, you won't exclude the max value
        {
            availableZValues.Add(i);
        }

        for (int i = 0; i < 6; i++)
        {
            int randomIndex = Random.Range(0, availableZValues.Count);
            float randomZ = availableZValues[randomIndex];
            availableZValues.RemoveAt(randomIndex);

            float numSteps = Mathf.Floor(randomZ / StepZSize);
            float newRandomZ = numSteps * StepZSize;

            int RandomXCheck = Random.Range(0, 2);

            if (RandomXCheck == 0)
            {
                RandomXValue = -2.2f;
            }
            else if (RandomXCheck == 1)
            {
                RandomXValue = 2.2f;
            }

            Instantiate(GateSingle, new Vector3(RandomXValue, 0, newRandomZ), Quaternion.identity);
        }
    }

This option is very efficient when you don’t have a lot of possible values, like in this case.

->Option 2

Create a list of chosenZValues and, to assign a value to randomZ, make a for loop that chooses values until it finds one that hasn’t been used:

public void Spawn()
{
List chosenValues = new List();

    for (int i = 0; i < 6; i++)
    {
        float randomZ = 0;

        for (int k = 0; k < 1000; k++)
        {
            float randomValue = Random.Range(minZValue, maxZValue);

            if(chosenValues.Contains(randomValue) == false)
            {
                randomZ = randomValue;
                break;
            }
        }

        float numSteps = Mathf.Floor(randomZ / StepZSize);
        float newRandomZ = numSteps * StepZSize;

        int RandomXCheck = Random.Range(0, 2);

        if (RandomXCheck == 0)
        {
            RandomXValue = -2.2f;
        }
        else if (RandomXCheck == 1)
        {
            RandomXValue = 2.2f;
        }

        Instantiate(GateSingle, new Vector3(RandomXValue, 0, newRandomZ), Quaternion.identity);
    }
}

This option has to choose random values and check if the list contains them. That process is less efficient, because when checking if a list contains a value, unity has to check every item in that list, and it might happen that you choose a value that has already been chosen and have to repeat the process. However, let’s say that you wanted to choose values for z in a range of 0 to 10000000. In that case, filling the available values list like in the option 1 would be really inefficient. Option 2, though, would shine, because the probability of getting the same number is minimal, and checking if the number you’ve picked is contained in a small list of chosen values is way less expensive than looping from 0 to 10000000 to fill a list.

I hope I’ve managed to explain myself clearly, since English isn’t my native language… I hope this can help you!

Option 3: make a List<> of all your unique values. Then swap values 2 by 2 chosen randomly, say 1000 times (very, very fast). Then, assign sequentially the values to your objects, the values are now random AND unique. Here is an example from my own code:

    public void Initialisation()
   {
                       // Établir une liste de 7 clés possibles, de 1 (Blanche) à 7 (Verte)
                       // Clefs is the class for my keys, and contains the color of the key
                       // Clefs.KeyType is the color (0=none, then from 1 to 7, then 8 is the MasterKey)
        List<Clefs.KeyType> typesDeClefs = new List<Clefs.KeyType>;
        for (int i = 0; i < 7; i++)
        {
            typesDeClefs.Add((Clefs.KeyType)i+1);
        }

        mélangerClés(ref typesDeClefs);

        // 'portes' is the List<GameObject> of all my doors
        for (int i = 0; i < portes.Count; i++)
        {
            // DoorsScript controls doors, and holds a value for the needed key if any
            if (true == portes*.TryGetComponent(out DoorsScript doorsScript))*

{
portes_.InitWithKey(typesDeClefs*);
}
}
}
private void mélangerClés(ref List<Clefs.KeyType> maListe)
{
for (int i = 0; i < 1000; i++)
{
int n = Random.Range(0, maListe.Count);
int m;
do { m = Random.Range(0, maListe.Count); } while (m == n);
(maListe[m], maListe[n]) = (maListe[n], maListe[m]);
}
}*_