2

I'm trying to take two names from my array of names, print them out, then remove those elements from my array and continue iterating until the array is empty.

var i;

function runNames() {
  var names = ["John", "Joe", "Bobby", "Sam", "Don", "Lemo"];
  for (i = names.length - 1; i >= 0; i = i - 2) {
    if (typeof names !== undefined && names.length > 0) {
      var item1 = 1;
      var item2 = 1;
      while (item1 == item2) {
        item1 = Math.random() * i;
        item2 = Math.random() * i;
        item1 = Math.floor(item1);
        item2 = Math.floor(item2);
      }
      document.getElementById("names").innerHTML += "<li>" + names[item1] + " " + names[item2] + "</li>";
      names.splice(item1, 1);
      names.splice(item2, 1);

    }
  }
}
<ul id="names"></ul>
<button onclick="runNames()">GENERATE TEAMS</button>

Console logs show the function working until the array empties, I guess I'm not handling that condition right. Thanks for any help.

  • `Math.random()` gives a floating-point random number between 0 and 1, and `Math.floor()` turns that to `0`. So, `item1` and `item2` always have the same value `0` and therefore the `while` loop keeps running indefinitely. – Nikhil Oct 29 '19 at 02:47

2 Answers2

2

A slightly different approach that I think is accomplishing what you want:

function generateTeams() {
  const node = document.getElementById('names');
  while(node.firstChild) {
    node.removeChild(node.firstChild);
  }
  
  const names = ["John","Joe","Bobby","Sam","Don","Lemo","Tim"];
  const teams = [];

  let team = [];

  while(names.length > 0) {
    if(names.length === 1 && team.length === 0) {
       teams.push([names[0]]);
       break;
    }

    const i = Math.floor(Math.random()*names.length);
    team.push(names[i]);
    names.splice(i,1);

    if(team.length === 2) {
      teams.push(team);
      team = []
    }
  }

  teams.forEach(team => {
      const t = document.createElement('li');
      t.innerText = team[0];

      if(team.length > 1) t.innerText += ', ' + team[1];

      document.getElementById('names').appendChild(t);
  });
}
<button onClick="generateTeams()">GENERATE TEAMS</button>
<ul id="names"></ul>

I take one name out at a time so I don't have to worry about getting two unique random numbers. I then keep a separate array as the current team that I put that one name into, until it has two, at which point I can add it to the teams array. If there is one name left over, they will be added as a solo team.

Anthony
  • 6,422
  • 2
  • 17
  • 34
1

Your code isn't working because Math.random() gives a floating-point random number between 0 and 1, and Math.floor() turns that to 0. So, item1 and item2 always have the same value 0 and therefore the while loop keeps running indefinitely.


Another approach is shuffling the array and taking two adjacent names to form a team.

I'm using modern version of Fisher-Yates shuffle algorithm from this answer.

// Modern version of Fisher-Yates shuffle algorithm.
function shuffle(a) {
  var j, x, i;
  for (i = a.length - 1; i > 0; i--) {
    j = Math.floor(Math.random() * (i + 1));
    x = a[i];
    a[i] = a[j];
    a[j] = x;
  }
  return a;
}

function generateTeams() {
  let names = ["John", "Joe", "Bobby", "Sam", "Don", "Lemo", "Bill"];
  let teams = [];

  // Shuffle the array in-place.
  shuffle(names); 

  // Take two adjacent names at a time to form a team.
  for (let i = 0; i < names.length; i = i + 2) {
    let a = names[i];
    let b = names[i + 1];

    if (b) {
      teams.push(a + ", " + b);
    } else {
      teams.push(a);
    }
  }
  
  // Clear existing list.
  document.getElementById("names").innerHTML = "";
  
  // Display new list.
  teams.forEach(team => {
    let listItem = document.createElement('li');
    listItem.innerText = team;
    document.getElementById("names").appendChild(listItem);
  });
}
<button onclick="generateTeams()">GENERATE TEAMS</button>
<ul id="names"></ul>
Nikhil
  • 6,493
  • 10
  • 31
  • 68