2

Please refer below code.

for (var i = 0; i < elements.length; i++) 
{
     //var element = elements[Math.floor(Math.random()*elements.length)];
     this.animateSymbol(elements[Math.floor(Math.random()*elements.length)]);
}

elements array contains list of svg elements(circle/path/ellipse etc). I want to select the random element from elements array.

it's return the same element in some cases I want to select the element randomly no need to select the same element again. Need to select different element from that array.

What's the problem ? Why its returning same index and same element ?

Thanks,

Siva

2
  • 2
    Nothing says the random number can't be the same as a previous random. Commented Jun 11, 2013 at 9:29
  • are you sure elements contains more than one element? Do a console.log(elements.length) . Commented Jun 11, 2013 at 9:30

5 Answers 5

8

Random numbers are random. There's no guarantee you won't get the same random number twice. In fact, when you convert the random numbers to a limited range of integers, it's quite likely you will get the same number twice.

You can fix this by copying the array and then each time you get a value from the array, remove it. Let's also break out the code that generates the random index as a separate function; it's handy in other situations too:

// Return a random integer >= 0 and < n
function randomInt( n ) {
    return Math.floor( Math.random() * n );
}

var copy = elements.slice();
while( copy.length ) {
    var index = randomInt( copy.length );
    this.animateSymbol( copy[index] );
    copy.splice( index, 1 );
}

And just for fun, here's another way you could code that loop:

var copy = elements.slice();
while( copy.length ) {
    var index = randomInt( copy.length );
    this.animateSymbol( copy.splice( index, 1 )[0] );
}

Either one does the same thing. I kind of like the step by step approach for clarity, but it can be quite handy that the .splice() method returns an array of the element(s) you delete.

Here's a version of the code you can paste into the JavaScript console to test:

// Return a random integer >= 0 and < n
function randomInt( n ) {
    return Math.floor( Math.random() * n );
}

var elements = [ 'a', 'b', 'c', 'd', 'e' ];
var copy = elements.slice();
while( copy.length ) {
    var index = randomInt( copy.length );
    console.log( copy.splice( index, 1 )[0] );
}
console.log( 'Done' );

It's also worth a look at Xotic750's answer. It uses the Fisher-Yates shuffle which randomizes an array in place. This would likely be more efficient for a very lengthy array.

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

8 Comments

thanks for your reply. but i have checked in console window same random numbers will be printed in that window. why ?
@SivaRajini - Not sure what you are referring to. I added a version of the code that's ready to paste into the JavaScript console. It seems to work OK.
whether i can use your code in for loop for(var i=0; i<elements.length;i++){ your javascript code}
@michael since you are removing the each element from array whether it will affect the for loop ?
No, this code already has the loop in it. You don't need another loop around it. Paste that last example into the JavaScript console as-is and see how it works.
|
2

So what you want is akin to a deck of cards, you shuffle them and take them one by one and therefore they are never repeated.

I would use something like the following for your problem, uses a standard Fisher-Yates shuffle.

function shuffle(obj) {
  var i = obj.length;
  var rnd, tmp;

  while (i) {
    rnd = Math.floor(Math.random() * i);
    i -= 1;
    tmp = obj[i];
    obj[i] = obj[rnd];
    obj[rnd] = tmp;
  }

  return obj;
}

var elements = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var randomised = elements.slice();
shuffle(randomised);

randomised.forEach(function(element) {
  console.log(element);
});

Comments

1

It is because you are using random there is no assurance that same number will not be repeated.

In your case I would suggest you to use some sort of shuffle to create a random order array.

You can find such method here

1 Comment

+1 for shuffle, this would also be my interpretation of the problem described.
1

Try capturing the random numbers generated and checking that you are not using them over again.

Here is a quick object I created for this purpose:

function PersistentRandom(exclusiveUpperBounds){
  this.spent = [];
  this.bounds = exclusiveUpperBounds;
}

PersistentRandom.prototype.getValue = function(){
    if(this.spent.length != this.bounds -1){
        var tmp = Math.floor(Math.random()* this.bounds);
        if(this.spent.indexOf(tmp) == -1){
            this.spent.push(tmp);
            return tmp;
        }else{
            return this.getValue();
        }
    }else{
        //If all numbers are used reset and start again
        this.spent = [];
        return this.getValue();
    }
};

//Usage
var pr = new PersistentRandom(11);

var x = 0;
while(x < 15){
   console.log(pr.getValue());
   x++;
}

Working Example http://jsfiddle.net/zasdj/

1 Comment

+1 for an alternative solution, could set 'this.spent.length = 0;´ rather than ´this.spent = [];´ as an improvement, but better than the removing element suggestions though a little over complicated I feel and relies on Array.indexOf (though shims are available). The bonus of this solution is the reset and start again.
-1

So you want a random element each time? but never the same element twice?

try this:

for (var i = 0; i < elements.length; i++) {
     //var element = elements[Math.floor(Math.random()*elements.length)];
     var index = Math.floor(Math.random()*elements.length);         
     this.animateSymbol(elements[index]);   
     elements.splice(index, 1);
}

this will remove the item from array once it has been selected

1 Comment

-1, this does not work because the elements array length gets shorter each time you remove an element from the array. The solution would be to reverse the for loop so that it counts downwards. jsfiddle.net/Xotic750/H8wbr

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.