4

I am new to JavaScript and I would like to get three random elements out of my array, which need to be different. I already managed to get three different elements, then I tried to take one element only once via the split method. But apparently this doesn't really work, there are probably a lot of mistakes since this is one of my first scripts. Also it sometimes says "undefined".

http://jsfiddle.net/t4mtpm50/

HTML:

<span id="tot1"></span>, <span id="tot2"> und </span> und <span id="tot3"></span>

Javascript:

function getNumber() {
    random = Math.floor(Math.random() * students.length);
    students.splice(random,1);
    return random;
}

students = new Array("Paul", "Jan", "Fabian D.", "Fabian K.", "Lennard", 
                            "Robin", "Angelique", "Joyce", "Sarah", "Ajlin",
                            "Enes", "Leon", "Boran", "Joshua")    

getNumber();
tot1 = students[random];
getNumber();
tot2 = students[random];
getNumber();
tot3 = students[random];

document.getElementById('tot1').innerHTML = tot1;
document.getElementById('tot2').innerHTML = tot2;
document.getElementById('tot3').innerHTML = tot3;
Simon Mathewson
  • 713
  • 6
  • 20
  • 1
    tot1 = students[random] when that statement hits, random is undefined. random is a local variable inside the getNumber function but once that function exits, that local variable is no longer accessible. Should be tot1 = students[getNumber()]; or var RandomNumber = getNumber(); tot1 = students[RandomNumber]; – frenchie Nov 23 '14 at 16:45
  • 1
    @frenchie Without a `var` or similar keyword to declare `random` as local, it will leak out as a global. http://stackoverflow.com/questions/1470488/ – Jonathan Lonowski Nov 23 '14 at 17:03
  • normally you access `return` variables like this: `var my_return_var = getNumber();` like @JonathanLonowski mentioned, your vars behave like global vars which can easily lead to problems in larger codes. – low_rents Nov 23 '14 at 17:10
  • if my solution doesnt work for you , please let me know. – ProllyGeek Nov 23 '14 at 17:12
  • 1
    Welcome to StackOverflow! Please see ["Should questions include “tags” in their titles?"](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), where the consensus is "no, they should not". –  Nov 23 '14 at 17:43
  • @AndreasNiedermair Thank you, I forgot that. – Simon Mathewson Nov 23 '14 at 17:50

4 Answers4

7

By using .splice(), the randomly selected name is actually being removed before it's retrieved, making random instead refer to the next name in the collection:

var students = [ "Paul", "Jan", "Fabian D." ];
var random = 1;

console.log(students[random]); // "Jan"

students.splice(random, 1);

console.log(students);         // [ "Paul", "Fabian D." ]
console.log(students[random]); // "Fabian D."

The "it sometimes says 'undefined'" happens when random tries to refer to the last element:

var students = [ "Paul", "Jan", "Fabian D." ];
var random = 2;

console.log(students[random]); // "Fabian D."

students.splice(random, 1);

console.log(students);         // [ "Paul", "Jan" ]
console.log(students[random]); // undefined, random is now out-of-bounds at 2

You could put to use the return value of .splice(), which is a collection of the removed elements, redefining getNumber() to instead return an element rather than an index:

function getStudent() {
    var random = Math.floor(Math.random() * students.length);
    return students.splice(random, 1)[0]; // return the 1st and only removed element
}

var tot1 = getStudent(); // "Fabian D."
var tot2 = getStudent(); // "Enes"
var tot3 = getStudent(); // "Joyce"

http://jsfiddle.net/6gox6L1t/

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
5

I think this would be a nicer, cleaner and shorter solution:

function getStudent(students) {
    var random = Math.floor(Math.random() * (students.length));
    var my_student = students.splice(random,1);
    return my_student;
}

var students = new Array("Paul", "Jan", "Fabian D.", "Fabian K.", "Lennard", 
                            "Robin", "Angelique", "Joyce", "Sarah", "Ajlin",
                         "Enes", "Leon", "Boran", "Joshua");


document.getElementById('tot1').innerHTML = getStudent(students);
document.getElementById('tot2').innerHTML = getStudent(students);
document.getElementById('tot3').innerHTML = getStudent(students);


you pass the current students-array to the getStudent() function so you avoid having global variables in your script. splice returns the element removed, so you got your student-name there and return it.

edit2: I was wrong about the -1 on the .length. 1 is an exclusive result of Math.random(), so you have been right with that.

http://jsfiddle.net/northkildonan/38rf42f7/1/

edit: this method completely avoids using global variables in your script.

low_rents
  • 4,481
  • 3
  • 27
  • 55
3

try this :

 students = new Array("Paul", "Jan", "Fabian D.", "Fabian K.", "Lennard",                   "Robin", "Angelique", "Joyce", "Sarah", "Ajlin",
"Enes", "Leon", "Boran", "Joshua")    


var arr = []
while(arr.length < 3){
  var randomnumber=Math.ceil(Math.random()*students.length-1)
  var found=false;
  for(var i=0;i<arr.length;i++){
    if(arr[i]==randomnumber){found=true;break}
  }
  if(!found)arr[arr.length]=randomnumber;
}
console.log(arr.valueOf());

tot1 = students[arr[0]];

tot2 = students[arr[1]];

tot3 = students[arr[2]];

document.getElementById('tot1').innerHTML = tot1;
document.getElementById('tot2').innerHTML = tot2;
document.getElementById('tot3').innerHTML = tot3;

please note that length should be decrmented by 1 , because index starts at 0.

http://jsfiddle.net/t4mtpm50/6/

ProllyGeek
  • 15,517
  • 9
  • 53
  • 72
  • 2
    The code does not even try to prevent the occurrence of a name more than once. – Jukka K. Korpela Nov 23 '14 at 16:58
  • @JukkaK.Korpela ok im sorry , fixed my answer. – ProllyGeek Nov 23 '14 at 17:08
  • Thanks a lot, this seems to work. Could you maybe tell me how exactly this works? I don't really get it :) – Simon Mathewson Nov 23 '14 at 17:14
  • 1
    @SimonMathewson the algorithm is really simple , i created an empty array and set the length to 3 ( count of how many different random numbers you want ) , created a loop where random numbers are generated , when a number is generated it iterated the array to check if similar number was created before , if so it will generate new number ,and so on , till no similar number is found , finally use the array elements to refer to your original array. if my answer is correct please mark it as correct one. – ProllyGeek Nov 23 '14 at 17:18
1

Another option is to shuffle the whole list of students and then pick the first three from the shuffled set. (The shuffle function here is adapted from https://stackoverflow.com/a/6274398/567595.)

function shuffle(array) {
    var i, temp, j;
    for (i = array.length; i; i--) {
        j = Math.floor(Math.random() * i);
        temp = array[i - 1];
        array[i - 1] = array[j];
        array[j] = temp;
    }
}
students = ["Paul", "Jan", "Fabian D.", "Fabian K.", "Lennard", 
                            "Robin", "Angelique", "Joyce", "Sarah", "Ajlin",
                            "Enes", "Leon", "Boran", "Joshua"];
shuffle(students);
document.getElementById('tot1').innerHTML = students[0];
document.getElementById('tot2').innerHTML = students[1];
document.getElementById('tot3').innerHTML = students[2];

http://jsfiddle.net/4o897kwa/1

Community
  • 1
  • 1
Stuart
  • 9,597
  • 1
  • 21
  • 30