Selection list from Array Unity - Random - GameObjects array

After creating a GameObjects array (checkpoints), I want to take just some of its values to set them as valid checkpoints, with no repeated values. I was looking for an answer in internet but I didn’t got an easy to understand solution.

using System.Collections.Generic;
using UnityEngine;

public class CheckpointsManager : MonoBehaviour
{
    private GameObject[] checkpoints;

    private List<int> numbersList1;
    private List<int> numbersList2;

    void Start()
    {
        // Create an array with all GOs with tag "Checkpoint"
        checkpoints = GameObject.FindGameObjectsWithTag("Checkpoint");
        SetValidCheckpoint();
    }

    private void SetValidCheckpoint()
    {
        // create Lists objects
        numbersList1 = new List<int>();
        numbersList2 = new List<int>(); //list with selected numbers

        // Add numbers to numbersList1 using GOs array.Length (checkpoints.Length)
        // checkpoints.Length is the number of total checkpoints
        for (int i = 0; i < checkpoints.Length; i++)
            numbersList1.Add(i);

        // *** print numbersList1 values, just for checking them out...
        // foreach (int num in numbersList1)
        // Debug.Log("numberslist1: " + num);

        // *for loop used to add numbers to numbersList2 and checkout values
        // numbersList2 keeps the valid checkpoints values
        // if the random value is repeated (if it's already contained in numbersList2)
        // it is not added, and the loop counter is not increased

        int n = 4; // number of valid (desired) checkpoints
        for (int i = 0; i < n;) // i++ is applied only if the number is not repeated
        {
            int randNum = Random.Range(0, numbersList1.Count);

            // just for checking in console
            Debug.Log("choosen number: " + randNum);

            if (!numbersList2.Contains(randNum)) // if the list2 doesn't contain the randNum
            {
                numbersList2.Add(randNum); // needed because we need to check out if number is repeated
                checkpoints[randNum].tag = "ValidCheckpoint"; // change GO tag
                i++; // increase the for loop counter
            }
            else // if the number is repeated
                Debug.Log("number " + randNum + "is already included in numbersList2");

            // just for checking out in console
            Debug.Log("n2 list count: " + numbersList2.Count);

            // just for checking out in console
            foreach (int num in numbersList2)
                Debug.Log("+++ numbers in numberslist2: " + num);

        }
    }
}

Code without comments and others

using System.Collections.Generic;
using UnityEngine;

public class CheckpointsManager : MonoBehaviour
{
    private GameObject[] checkpoints;

    private List<int> numbersList1;
    private List<int> numbersList2;

    void Start()
    {
        checkpoints = GameObject.FindGameObjectsWithTag("Checkpoint");
        SetValidCheckpoint();
    }

    private void SetValidCheckpoint()
    {
        numbersList1 = new List<int>();
        numbersList2 = new List<int>(); 

        for (int i = 0; i < checkpoints.Length; i++)
            numbersList1.Add(i);

        int n = 4; 
        for (int i = 0; i < n;) 
        {
            int randNum = Random.Range(0, numbersList1.Count);

            if (!numbersList2.Contains(randNum)) 
            {
                numbersList2.Add(randNum); 
                checkpoints[randNum].tag = "ValidCheckpoint"; 
                i++; 
            }
        }
    }
}

Now you have 4 not repeated random numbers that can be used as index for a list or array of valid checkpoints, and instantiating as well.
You can copy/paste in VS for better visualization.