0

I'm trying to create a function that accomplish the following purpose:

enter image description here

In plain words, I want a function that takes n arguments, each argument (three arguments in the above example, each array has a different colour) being an array with the same length = m. I want the function to return an array with a length = n, and each item would be an array with a length = m.

The problem for now is that I splice the array I take randomly an item from, so it messes up the length of the array and only returns half the data expected. I could potentially replace the value I splice with "-1" for example and verify each random item I choose but that seems like a dirty way of getting things done.

//Generates an array of n items randomly taken from m arrays given as arguments where arrays length equal n.
function arrayDistributor(...args) {
    try {
        //Copying the array of arguments
        let arg = args.slice();

        //Verification to see if an argument is an array of different length than the others
        for (let i = 0; i < arg.length; ++i) {
            //Appliying the verification if it's not the last array item
            if (i !== (arg.length - 1)) {
                //Actual verification
                if (arg[i].length !== arg[i + 1].length) {
                    throw "An argument doesn't have the same length as others.";
                }
            }
        }

        let r = [];
        //Looping through the first argument
        for (let i = 0; i < (arg[0].length); ++i) {
            let arr = [];
            //Looping through all the arguments
            for (let j = 0; j < arg.length; ++j) {
                //Selecting a random index in the j argument
                let k = getRandomInt(0, (arg[j].length - 1));
                //Pushing the item inside the new array
                arr.push(arg[j][k]);
                //Removing the item from the initial array !problem here
                arg[j].splice(k, 1);
            }
            //Pushing the array to the result array
            r.push(arr);
        }
        return r;
    } catch (e) {
        console.log(e);
    }
};

//Return a random integer between an inclusive interval
function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
isherwood
  • 58,414
  • 16
  • 114
  • 157
BFlat
  • 174
  • 11

2 Answers2

1

This is easier when you randomly shuffle each of the subarrays. Then for each output subarray, combine the values from the shuffled subarrays that occur at the same index, and do this for each index:

function shuffle(a) { /* function taken from https://stackoverflow.com/a/6274381/5459839 */
    var j, x, i;
    for (i = a.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = a[i];
        a[i] = a[j];
        a[j] = x;
    }
    return a;
}

function randomCombi(data) {
    let shuffled = data.map(row => shuffle([...row]));
    return shuffled[0].map((_, i) => shuffled.map(row => row[i]));
}

// sample data

let data = [["a1", "b1", "c1", "d1"],
            ["a2", "b2", "c2", "d2"],
            ["a3", "b3", "c3", "d3"]]
            
console.log(randomCombi(data)); 
            
trincot
  • 317,000
  • 35
  • 244
  • 286
1

Since the array is nested, you can take advantage of the parent array's map function

function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}

function distributeArrays(arrays,n,m){
  let new_array = [];
  for( let i = 0; i < n; i++ ){ 
    new_array.push(arrays.map(x => x[getRandomInt(m)]));
  }
  return new_array;
}

Example

x = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
distributeArrays(x,4,3);
Array(4) [ (4) […], (4) […], (4) […], (4) […] ]
​
0: Array(4) [ 2, 6, 10, … ]
​
1: Array(4) [ 2, 7, 11, … ]
​
2: Array(4) [ 2, 6, 9, … ]
​
3: Array(4) [ 2, 6, 11, … ]
​
length: 4
Jesse R
  • 61
  • 4