0

I have the following function that can pull out a random index from an array without repeating the index and keeps pulling them out until all have been used and then resets itself and starts re-using them. It also tries to make sure that the last one that was pulled out isn't the same as the next one pulled out on the reset so that you don't ever have the same index come out in a row.

var listIndexes = [];
var lastIndex;

function getRandomIndex(indexes)
{
    if (!listIndexes.length) {
        for (var i = 0; i < indexes; i++) {
            listIndexes.push(i);
        }
    }

    var randomIndex = Math.floor(Math.random() * listIndexes.length);
    var uniqueIndex = listIndexes[randomIndex];

    listIndexes.splice(randomIndex, 1);

    if(lastIndex && uniqueIndex == lastIndex)
    {
        listIndexes = [];
        getRandomIndex(indexes);
        return;
    }

    lastIndex = uniqueIndex;

    return uniqueIndex;
}

var index = getRandomIndex(5);

console.log(index);

However when it hits the code: if(lastIndex && uniqueIndex == lastIndex) it causes it to return undefined for the index. So the way I'm trying to exit the function and re-call the function to try again isn't working as planned.

How can I exit the current function call and re-call the function to get a new random index that isn't the same as the lastIndex. Note that the lastIndex is kept intact until the new index isn't the same regardless of how many times the function is called.

3 Answers 3

2

Try this:

if(lastIndex && uniqueIndex == lastIndex)
    {
        listIndexes = [];
        return getRandomIndex(indexes);
    }
Sign up to request clarification or add additional context in comments.

Comments

1

just change your empty return to run the function again:

return getRandomIndex(indexes);

Comments

1

The approach of rethrowing the die when you don't get the result you want is not optimal and when the random number isn't so random (tends to repeat the same number), then you're cycling unnecessarily.

Try this:

function RandEleGenerator(list) {
    var lastChosen;
    var currentList = list.slice();

    function randomIndex() {
        return Math.floor(Math.random() * currentList.length);
    }
    return function() {
        // Choose element
        var index = randomIndex();
        var obj = currentList[index];

        // Remove it from current list
        currentList.splice(index, 1);
        if(currentList.length == 0) {
            // If empty, restore list
            currentList = list.slice();

            // But not without removing last chosen element
            index = currentList.indexOf(obj);
            currentList.splice(index, 1);
        }
        return obj;
    };
}

Usage:

var reg = new RandEleGenerator([1,2,3]);
reg();   // 3
reg();   // 2
reg();   // 1
reg();   // 2
reg();   // 3
reg();   // 2
reg();   // 1

The chosen element is removed from the list so it cannot be rechosen. In order to guarantee that a value isn't repeated when the list ends, the list is recreated and the last element chosen is removed from the list immediately. The process then continues randomly choosing elements to remove from the list.

Edit: In order to say, generate an array to pass to RandEleGenerator, the following code is sufficient:

var arrToPass = [];
for (var i = 0; i < 3; i++) {
    arrToPass.push(i);
}
var reg = new RandEleGenerator(arrToPass);

3 Comments

Can this work with just a number? As I don't want to pass it the actual array just the number, so in your example, I'd just want to pass it RandEleGenerator(3);
@Cameron You already have the code to construct the array [1, 2, 3] from just the number 3. for (var i = 0; i < indexes; i++) { listIndexes.push(i); } You can perform it prior to calling RandEleGenerator or you can do it internally, taking instead the number 3 as a parameter (but I would always recommend the more flexible of the two, which in this case is the former).
Can you show me an example of how I'd do that, as I'm not following what you mean. Cheers pal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.