1

I wrote a simple enough randomize function that loops through the elements in an array and displays them one after the other.

See it here.

function changeSubTitle() {
    var whatAmI = ["Webdesigner", "Drummer", "Techie", "Linguistics student", "Photographer", "Geek", "Coder", "Belgian", "Batman", "Musician", "StackExchanger", "AI student"];
    setTimeout(function () {
        $(".page-header > h2").animate({
            "opacity": 0
        }, 700, function () {
            $(this).text(whatAmI[Math.floor(Math.random() * whatAmI.length)]);
            $(this).animate({
                "opacity": 1
            }, 700, changeSubTitle);
        });
    }, 1000);
}

However, obviously it is very well possible that the same element is displayed twice, one immediately after the other. This happens because I randomize the array each time I call the function. How would I prevent an element to be displayed two times right after each other?

I suppose the most straightforward way to do this is to get the randomize function out the loop, run the loop and each time an element is called, remove the index from the array and refill the array when it's empty. A lot of questions on SO consider this problem, but not as specific as mine: I'm not sure how to do this in the loop to display each element.

1
  • what i would do is first shuffle the array and, then show each element one by one as you would normally do. check this stackoverflow.com/questions/6274339/… on how to shuffle Commented Sep 4, 2015 at 9:46

3 Answers 3

3

Stop upvoting please :-D

The following answer is better: https://stackoverflow.com/a/32395535/1636522. The extended discussion between me and Tim enlighten on why you should avoid using my solutions. My answer is only interesting from this point of view, hence, it does not deserve any upvote :-D


You could save the last integer and "while" until the next one is different:

var i, j, n = 10;
setInterval(function () {
  while ((j = Math.floor(Math.random() * n)) === i);
  document.write(j + ' ');
  i = j;
}, 1000);

Or even simpler, just add 1... :-D Modulo n to prevent index overflow:

var i, j, n = 10;
setInterval(function () {
  j = Math.floor(Math.random() * n);
  if (j === i) j = (j + 1) % n;
  document.write(j + ' ');
  i = j;
}, 1000);

First solution applied to your code:

var whatAmI = ["Webdesigner", "Drummer", "Techie", "Linguistics student", "Photographer", "Geek", "Coder", "Belgian", "Batman", "Musician", "StackExchanger", "AI student"];
var j;
var i = 1; // since you start with "Drummer"
var n = whatAmI.length;

function changeSubTitle() {
  setTimeout(function () {
    while ((j = Math.floor(Math.random() * n)) === i);
    $(".page-header > h2").animate({
      "opacity": 0
    }, 700, function () {
      $(this).text(whatAmI[j]);
      $(this).animate({
        "opacity": 1
      }, 700, changeSubTitle);
    });
  }, 1000);
  i = j;
}

changeSubTitle();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header class="page-header">
     <h1>Bananas</h1>
     <h2>Drummer</h2>
</header>

Sign up to request clarification or add additional context in comments.

4 Comments

In which case i is an index from the array, and n the length of the array, right? Could you apply it to my code?
Yes, this works (I think)! Could you explain what the while loop does? It might seem straightforward, but I can't wrap my head around it!
@BramVanroy I have updated with a demo. Care to set i according to the value you want to display first. About the little loop: while ((j = something) === i); sets "j" to something, compares with i then redo if j === i. Is it clear enough? :-/
@BramVanroy It was getting too long for here, I've posted it as another answer. You can run it through in my head though. If n is 3 and i is 1 then you have a 1/3 chance of generating a 0 and a 2/3 chance of generating a 2
1

To give an even chance of all elements except the previous one being used do the following:

var i, j, n = 10;
setInterval(function () {
  // Subtract 1 from n since we are actually selecting from a smaller set
  j = Math.floor(Math.random() * (n-1)); 
  // if the number we just generated is equal to or greater than the previous
  // number then add one to move up past it
  if (j >= i) j += 1;
  document.write(j + ' ');
  i = j;
}, 1000);

The comments in the code should explain how this works. The key thing to remember is that you are actually selecting from 9 possible values, not from 10.

You should initialize i to be a random element in the array before starting.

For a simple walk through on a 3 element array with the second element selected:

i=1, n=3

The random result gives us either 0 or 1.

If it is 0 then j >= i returns false and we select element zero

If it is 1 then j >= i returns true and we select the third element.

You can do the same walk through with i being 0 and and i being 2 to see that it never overruns the buffer and always has an equal chance to select all other elements.

You can then extend that same logic to an array of any size. It works exactly the same way.

2 Comments

Thanks for the explanation. Since i isn't defined in the first run, won't if (j >= i) j += 1; throw an error?
0
var whatAmI = ["Webdesigner", "Drummer", "Techie", "Linguistics student", "Photographer", "Geek", "Coder", "Belgian", "Batman", "Musician", "StackExchanger", "AI student"];

var prev = 1; //1 because "drummer" is the first array element displayed in the HTML

function getIndex(){
    var next = Math.floor(Math.random() * whatAmI.length);
    if(next==prev)
        return getIndex();
    else {
        prev = next;
        return next;
    }       
}

function changeSubTitle() {
    setTimeout(function () {
        $(".page-header > h2").animate({
            "opacity": 0
        }, 700, function () {
            $(this).text(whatAmI[getIndex()]);
            $(this).animate({
                "opacity": 1
            }, 700, changeSubTitle);
        });
    }, 1000);
}
changeSubTitle();

Try this method.

Comments

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.