skip to Main Content

The script:

let col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
for(let i = 0; i < 5; i++) {
    const random = Math.floor(Math.random() * col1.length + 1)
    const index = col1.indexOf(random)
    const number = col1.at(index)
    col1.splice(index, 1)
    console.log(number)
}
for(let i = 0; i < 5; i++) {
    const random = Math.floor(Math.random() * col2.length + 1)
    const index = col2.indexOf(random)
    const number = col2.at(index)
    col2.splice(index, 1)
    console.log(number)
}

The first for loop always generates 5 random numbers from the first array. But the second for loop always shows the same results (30, 29, 28, 27, 26). What’s causing this behavior?

3

Answers


  1. You are trying to get the index of the value in col2. You have an array of 15 items. Your index will always be less than the 16 (the lowest number in your second set), and by extension, col2.indexOf(random) will always return -1, because your random value less than 16 is not in that array, and indexOf returns -1 if it cannot find the index of your supplied value. Splicing with -1 will return the last value in your array, hence why you get 30-26. See the MDN docs for indexOf:

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

    Login or Signup to reply.
  2. const random = Math.floor(Math.random() * col2.length + 1);
    

    generates a random integer between 0 and 15, since col2.length is 15. Then,

    const index = col2.indexOf(random);
    

    always returns -1, since there isn’t any element with value random in col2. So then

    const number = col2.at(index);
    

    assigns always col2‘s last item to number, which changes each iteration since

    col2.splice(index, 1);
    

    removes col2‘s last element.

    If you want five different elements from each array, you can just do:

    let col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 
    let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
    
    for(let i = 0; i < 5; i++) {
        const index = Math.floor(Math.random() * col1.length);
        const number = col1.at(index);
        col1.splice(index, 1);
        console.log(number);
    }
    for(let i = 0; i < 5; i++) {
        const index = Math.floor(Math.random() * col2.length);
        const number = col2.at(index);
        col2.splice(index, 1);
        console.log(number);
    }

    EDIT: removed the +1 in Math.floor() to stay within range.

    Login or Signup to reply.
  3. Your second for loop effectively ends up calling at() with -1 five times:

    const number = col2.at(-1)
    

    When you pass -1 to .at() it gives you the last element in your array, and and since the following .splice(-1, 1) call removes the last element from col2, the next iteration will give you the next last element and so on.

    The main issue with your code is that you’re treating random as an element within your array, when really it’s an index (if you remove the +1). This ends up with your .indexOf() code not being able to find the random element in your array, and thus setting index to -1. The only reason it happens to work in your first example is because your elements are consecutive starting from 1, so random in that case just so happens to match up with an element from your array. But in the more general case (like col2), that won’t be the case.

    Instead, you can get your random index, access the element at that index using bracket notation (no need for .indexOf() or .at()), and then remove the element from your source array (to avoid doubling-up on the same element):

    let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
    for(let i = 0; i < 5; i++) {
        const randomIndex = Math.floor(Math.random() * col2.length);
        const number = col2[randomIndex];
        col2.splice(randomIndex, 1)
        console.log(number);
    }

    Or, an alternative approach would be to shuffle your array, and then use .slice() to get the first n elements:

    let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
    
    // Source; https://stackoverflow.com/a/12646864/5648954
    function shuffle(array) {
        for (var i = array.length - 1; i >= 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }
    
    const n = 5;
    const res = shuffle(col2).slice(0, n);
    console.log(res);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search