Search code examples
javascriptarraysrandom

Randomly select 2 elements from an array where each element is selected 4 times and the pairs are not duplicated


I am looking to select 2 elements from an array and pair them up. Each element should be selected exactly 4 times and each pair should be unique. For example, if I have the following array:

arr = [p1, p2, p3, p7, p10, p15, p17, p19, p22, p27]

I want to generate something similar to the following:

result: [[p2,p19],[p27,p10],[p15,p3],[p19,p17],[p27,p7],[p3,p17],[p27,p22],[p22,p3],[p15,p1],[p7,p2],[p19,p1],[p17,p15],[p15,p27],[p3,p7],[p10,p22],[p17,p27],[p2,p3],[p27,p1],[p19,p22],[p2,p17]]

In what I have "working" I get unique pairs, however, I do not get exactly 4 instance of each element. I get the following instances for each element: p1 - 3, p2 - 4, p3 - 5, p7 - 3, p10 - 2, p15 - 4, p17 - 5, p19 - 4, p22 - 4, p27 - 6

Here is the array I am using:

let arr = [p1, p2, p3, p7, p10, p15, p17, p19, p22, p27];

Here is the function that I am using:

function selectUniquePairs(arr) {
    if (arr.length < 2) {
      return "Array must contain at least two elements.";
    }
  
    const selectedPairs = new Set();
    const result = [];
  
    for (let i = 0; i < arr.length * 2; i++) {
      let index1, index2;
      do {
        index1 = Math.floor(Math.random() * arr.length);
        index2 = Math.floor(Math.random() * arr.length);
      } while (index1 === index2 || selectedPairs.has(JSON.stringify([index1, index2].sort())));
  
      const pair = [arr[index1], arr[index2]];
      result.push(pair);
      selectedPairs.add(JSON.stringify([index1, index2].sort()));
    }
  
    return result;
}

Any help would be greatly appreciated.

I am wanting to do this in pure javascript, no additional libraries.


Solution

  • The count array is used to keep track of the number of times the arr item occurs in the selectedPairs set.

    let arr = ['p1', 'p2', 'p3', 'p7', 'p10', 'p15', 'p17', 'p19', 'p22', 'p27'];
    function selectUniquePairs(arr) {
        if (arr.length < 2) {
          return "Array must contain at least two elements.";
        }
      
        const selectedPairs = new Set();
        const result = [];
        let count=[];//array for keeping track of frequency of each arr element in selectedPairs
    
        for (let i=0;i<arr.length;i++){
            count.push(4);//each arr element should occur only 4 times
        }
      
        while (!count.every((elt)=>elt==0)){
            let index1, index2;
            do{
                do{
                    index1 = Math.floor(Math.random() * arr.length);
                }while(count[index1]==0);//will find another random element from arr if the element already occurred 4 times in selectedPairs
                do{
                    index2 = Math.floor(Math.random() * arr.length);
                }while(count[index2]==0);//will find another random element from arr if the element already occurred 4 times in selectedPairs
            }while(selectedPairs.has(JSON.stringify([index1, index2].sort())) || (index1 === index2));
            count[index1]--;
            count[index2]--;  //decrements their frequency each time the element from arr is used within a pair in selectedPairs
            const pair = [arr[index1], arr[index2]];
            result.push(pair);
            selectedPairs.add(JSON.stringify([index1, index2].sort()));
        }
        return result;
    }