1

I have an array with 30 values that will be randomly distributed between other 3 arrays. I made it work "almost" right, but the 3 arrays always come with a random quantity of elements and I need 2 of them with 8 elements and other with 14, how can I define that?

            const arrAll = [s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10]
            const arrCard = []
            const arrCent = []
            const arrSec = []

            arrAll.map(l => {
                let rand = Math.floor(Math.random() * 9000)
                rand <= 3000 ? arrCard.push(l) : rand <= 6000 ? arrCent.push(l) : arrSec.push(l);
            })
Peter O.
  • 32,158
  • 14
  • 82
  • 96

3 Answers3

1

One solution is that you shuffle the array as whole and then you just select number of elements into each of your array as you need.

This is the example (the shuffle function was copy pasted from How can I shuffle an array? )

function shuffle(a) {
    for (let i = a.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
    }
    return a;
}

function splitArrayRandomly(arr, sizes) {
  const shuffledArr = shuffle(arr);
  let pos = 0;
  const arrays = sizes.map(size => {
    const newArr = shuffledArr.slice(pos, pos + size);
    pos += size;
    return newArr;
  });
  
  return arrays;
}

const arr = [4, 7, 15, 22, 11, 6, 19];
// This option create 3 arrays, first of size 4, second of size 2 and last with size 1
const sizes = [4,2,1];

console.log(splitArrayRandomly(arr, sizes));

In your case, you put into sizes this array [8, 8, 14] and it returns you three arrays with these sizes. You can then put them into yours arrCard, arrCent, arrSec variables if needed.

libik
  • 22,239
  • 9
  • 44
  • 87
0

1) From Input array, create random order by generating random indexes with limiting the size of array.
2) Create output array of arrays (initialize) for same length as sizes array.
3) maintain o_idx (output index) to track which output array will need to push the element.
4) Once getting the r_idx (random index), then push the corresponding value (arr[r_idx]) to corresponding output array (output[o_idx]).

const randomOrderInSizes = (arr, sizes) => {
  const myRandom = () => Math.floor((Math.random() * 100) % arr.length);
  const temp = [];
  const output = sizes.map(() => []);
  let o_idx = 0;
  arr.forEach(() => {
    let r_idx = myRandom();
    while (temp.includes(r_idx)) {
      r_idx = myRandom();
    }
    temp.push(r_idx);
    
    if (sizes[o_idx] === output[o_idx].length) {
      o_idx += 1;
    }
    output[o_idx].push(arr[r_idx]);
  });
  return output;
};


const data = [21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
              11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
              31, 32, 33, 34, 35, 36, 37, 38, 39, 40];
              
const required = randomOrderInSizes(data, [8, 8, 14]);

console.log(required);
Siva K V
  • 10,561
  • 2
  • 16
  • 29
0
  1. Make a second array that maps out the distribution of the array:

    const dist = [8, 8, 14];
    

    That would be 3 arrays -- the first two with the length of 8 and the third array with the length of 14. In the demo that array is the second parameter.

  2. Next, randomly shuffle the main array. In the demo the main array is the first parameter. To randomly shuffle the main array, we'll use the Fisher-Yates Shuffle

  3. Finally, two for loops are used.

    1. The outer loop will create an empty array. It will iterate the length of the dist array. In the demo, that would be three times.

    2. The inner loop will .shift()* out a value from the main array (which has been randomly reordered (see #2)) and then .push() it into the array previously defined in the outer loop (see #3.1). Each inner loop will iterate the number of times indicated at the index position of the current outer loop iteration.

      Example (pseudo-code)

      /* On the second iteration of the outer loop, will be 8 */
      dist[1] = 8
      /* On the inner loop, it will take the values of the randomly reordered main  
      array in the range of 9 thru 16 */
      ["e9","i4","i10","s2","e8","i9","i3","i8"]
      

      *.shift() will take the value of an array at index 0 permanently. This is done so that the values from the main array are not duplicated in the sub-arrays

  4. Once an iteration of the inner loop is complete, that array will be .push()ed into the result array. Once the last inner loop has been completed, the result array is returned as a two dimensional array.

    Example (pseudo-code)

    /* Returned as a two dimensional array */
    result = [[8 values], [8 values], [14 values]]
    /* Assign variables to each sub-array */
    const cardArr = result[0];
    const centArr = result[1];
    const sectArr = result[2];
    

Demo

const main = ['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 'i1', 'i2', 'i3', 'i4', 'i5', 'i6', 'i7', 'i8', 'i9', 'i10', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'e10'];

const dist = [8, 8, 14];
 
function randomDistribution(array, dist) {
  let total = array.length, split = dist.length;
  let result = [], temp, index;

  while(total) {
    index = Math.floor(Math.random() * total--);
    temp = array[total];
    array[total] = array[index];
    array[index] = temp;
  }
  for (let subIdx = 0; subIdx < split; subIdx++) {
    let subArr = [];
    for (let reIdx = 0; reIdx < dist[subIdx]; reIdx++) {
      subArr.push(array.shift());
    }
    result.push(subArr);
  }
  return result;
}

let twoDArray = randomDistribution(main, dist);

console.log(JSON.stringify(twoDArray));

const cardArray = twoDArray[0];
const centArray = twoDArray[1];
const sectArray = twoDArray[2];

console.log(`cardArray: ${cardArray}`);
console.log(`centArray: ${centArray}`);
console.log(`sectArray: ${sectArray}`);
.as-console-row-code {
  word-break: break-word;
  overflow-x: hidden;
}
zer00ne
  • 41,936
  • 6
  • 41
  • 68